spring 到底怎么才能拿到原始的 body 啊? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
likeme
V2EX    Java

spring 到底怎么才能拿到原始的 body 啊?

  •  
  •   likeme 2023-12-01 11:57:01 +08:00 3130 次点击
    这是一个创建于 687 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我的接口

    腾讯签名示例

    尝试与腾讯实时音视频进行对接。从 request 中提取数据或通过 @RequestBody String body 获取,发现格式不符合原始格式,且缺少了\n 或\t 符号,导致签名不一致。确认使用的是示例中的密钥和签名值,并通过 Postman 进行了测试。

    第 1 条附言    2023-12-01 13:53:39 +08:00
    我怀疑破案了,因为我们公司的脚手架有对请求数据做一些过滤,所以导致无法拿到最原始的,我重新创建了一个 spring 脚手架,测试了是用 @RequestBody String body 就可以拿到原始的。
    13 条回复    2023-12-04 13:58:48 +08:00
    likeme
        1
    likeme  
    OP
       2023-12-01 11:58:07 +08:00
    chatgpt 已经问烂了,实在是没办法了发到 V2EX 让老哥们给看看。
    NULL2020
        2
    NULL2020  
       2023-12-01 12:08:00 +08:00
    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();
    }
    chendy
        3
    chendy  
       2023-12-01 12:11:55 +08:00
    随手测试了一下,除非做了什么特殊处理,否则 ReqeustBody String 拿到的就是原始字符串,特殊字符不会被去掉
    至于 /n 和 /t 被去掉,有没有可能是并没有被去掉只是打印看不到呢…
    lisongeee
        4
    lisongeee  
       2023-12-01 12:19:09 +08:00
    如果使用 @RequestBody ByteArray body 获取是否可行?
    infoscope
        5
    infoscope  
       2023-12-01 12:44:25 +08:00
    直接从 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);
    tring requestCOntent= new String(requestWrapper.getContentAsByteArray());
    checkSign(requestContent);
    chain.doFilter(requestWrapper, response);
    }
    rimwindy
        6
    rimwindy  
       2023-12-01 13:33:24 +08:00
    不行就再转一次吧,过来的 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"
    ```
    likeme
        7
    likeme  
    OP
       2023-12-01 13:41:07 +08:00
    @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);
    Masoud2023
        8
    Masoud2023  
       2023-12-01 13:48:16 +08:00
    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 的那套类型转换,这个往上好像有很多资料都提到过这个问题。
    likeme
        9
    likeme  
    OP
       2023-12-01 13:53:22 +08:00   1
    @Masoud2023 我怀疑破案了,因为我们公司的脚手架有对请求数据做一些过滤,所以导致无法拿到最原始的,我重新创建了一个 spring 脚手架,测试了是用 @RequestBody String body 就可以拿到原始的。
    Masoud2023
        10
    Masoud2023  
       2023-12-01 13:53:37 +08:00
    HttpServletRequestCopier copier = new HttpServletRequestCopier((HttpServletRequest) servletRequest);
    filterChain.doFilter(copier, servletResponse);
    xiaoxinTOm
        11
    xiaoxinTOm  
       2023-12-01 16:21:31 +08:00
    controller 拿的 body ?可能过滤器对请求体做了二次处理,处理过后的才放行到 controller 中,我以前看到的代码有这么做,你去看看过滤器把 filter 把
    likeme
        12
    likeme  
    OP
       2023-12-04 08:59:26 +08:00
    @xiaoxinTOm 是的,用的是 ruoyi 的框架,有一个过滤器导致的。
    bill110100
        13
    bill110100  
       2023-12-04 13:58:48 +08:00
    可以开 web trace 级 log ,然后打开 spring.mvc.log-request-details =true 就能在日志里看请求参数和载荷信息。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2574 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 45ms UTC 03:56 PVG 11:56 LAX 20:56 JFK 23:56
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86