我的接口
腾讯签名示例
尝试与腾讯实时音视频进行对接。从 request 中提取数据或通过 @RequestBody String body 获取,发现格式不符合原始格式,且缺少了\n 或\t 符号,导致签名不一致。确认使用的是示例中的密钥和签名值,并通过 Postman 进行了测试。
1
likeme OP chatgpt 已经问烂了,实在是没办法了发到 V2EX 让老哥们给看看。
|
2
NULL2020 350 天前
public static String getRequestBodyString(HttpServletRequest request) {
final int contentLength = request.getContentLength(); if (contentLength <= 0) { return null; } StringBuilder data = new StringBuilder(); String line; BufferedReader reader; try { reader = request.getReader(); while (null != (line = reader.readLine())) data.append(line); } catch (Exception e) { log.error("HttpServletRequest read line error."); } return data.toString(); } |
3
chendy 350 天前
随手测试了一下,除非做了什么特殊处理,否则 ReqeustBody String 拿到的就是原始字符串,特殊字符不会被去掉
至于 /n 和 /t 被去掉,有没有可能是并没有被去掉只是打印看不到呢… |
4
lisongeee 350 天前
如果使用 @RequestBody ByteArray body 获取是否可行?
|
5
infoscope 350 天前
直接从 HttpServletRequest 中拿
用 @RequestBody 映射的,SpringMCV 根据 Content-Type 选择对应的转换器进行转换,如: org.springframework.http.converter.StringHttpMessageConverter 只对 text/plain 生效 org.springframework.http.converter.json.MappingJackson2HttpMessageConverter 对 application/json 生效 如果对方请求不是 text/plain, 你拿到的 String 就不是原始的了 建议的验签方式应该是在 Filter 层,对业务代码无侵入 ContentCachingRequestWrapper @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 用 ContentCachingRequestWrapper 的目的时把请求体读出来的内容缓存起来,后续 SpringMVC 还可以再读一遍,原始的 InputStream 是不能重置再读的 ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper((HttpServletRequest) request); String requestContent = new String(requestWrapper.getContentAsByteArray()); checkSign(requestContent); chain.doFilter(requestWrapper, response); } |
6
rimwindy 350 天前
不行就再转一次吧,过来的 body 可能就是普通 JSON ,不是演示里那种压缩为一行的情况。
Demo: ```java public class Main { public static void main(String[] args) throws JsonProcessingException { String body = """ { "status": "OK", "data": [ { "id": 1, "name": "data1" }, { "id": 2, "name": "data2" } ] } """; // Jackson-databind -> pom.xml ObjectMapper mapper = new ObjectMapper(); String body2 = mapper.writeValueAsString(body); System.out.println("JSON to one line: " + body2); } } ``` Output: ```bash JSON to one line: "{\n\t\"status\": \"OK\",\n\t\"data\": [\n\t\t{\n\t\t\t\"id\": 1,\n\t\t\t\"name\": \"data1\"\n\t\t},\n\t\t{\n\t\t\t\"id\": 2,\n\t\t\t\"name\": \"data2\"\n\t\t}\n\t]\n}\n" ``` |
7
likeme OP @chendy 打印 body ,然后再将打印的 json 发送请求,controller 就拿不到原来的格式了,直接变成了一行,丢失了换行符了。
String body = "{\n" + "\t\"EventGroupId\":\t2,\n" + "\t\"EventType\":\t204,\n" + "\t\"CallbackTs\":\t1664209748188,\n" + "\t\"EventInfo\":\t{\n" + "\t\t\"RoomId\":\t8489,\n" + "\t\t\"EventTs\":\t1664209748,\n" + "\t\t\"EventMsTs\":\t1664209748180,\n" + "\t\t\"UserId\":\t\"user_85034614\",\n" + "\t\t\"Reason\":\t0\n" + "\t}\n" + "}"; System.out.println(body); |
8
Masoud2023 350 天前
https://github.com/yuhuachang/java-spring-boot-samples/blob/master/spring-rest-logging/src/main/java/com/example/restlogging/logging/HttpServletRequestCopier.java
你想要的应该是这个。 把这个放进 filter 链,然后在 controller 拿到 httpservletrequest ,强制转换到这个 HttpServletRequestCopier ,调用 getContentAsByteArray ,然后转成 utf-8 string 就行了。 靠 @RequestBody 我记得我之前的实践是怎么拿都拿不到最原始的 body ,他始终都会走一遍 Spring 的那套类型转换,这个往上好像有很多资料都提到过这个问题。 |
9
likeme OP @Masoud2023 我怀疑破案了,因为我们公司的脚手架有对请求数据做一些过滤,所以导致无法拿到最原始的,我重新创建了一个 spring 脚手架,测试了是用 @RequestBody String body 就可以拿到原始的。
|
10
Masoud2023 350 天前
HttpServletRequestCopier copier = new HttpServletRequestCopier((HttpServletRequest) servletRequest);
filterChain.doFilter(copier, servletResponse); |
11
xiaoxinTOm 350 天前
controller 拿的 body ?可能过滤器对请求体做了二次处理,处理过后的才放行到 controller 中,我以前看到的代码有这么做,你去看看过滤器把 filter 把
|
12
likeme OP @xiaoxinTOm 是的,用的是 ruoyi 的框架,有一个过滤器导致的。
|
13
bill110100 347 天前
可以开 web trace 级 log ,然后打开 spring.mvc.log-request-details =true 就能在日志里看请求参数和载荷信息。
|