@RequestBody取不到值?报请求体为空怎么办

项目场景:

我们在项目中经常会使用到@RequestBody这个注解来获取前端给的参数,方便又快捷,也不需要做类型转换,前端按照我们入参bean类的格式取传,我们直接就可以获取到并在代码中使用了,但是“老马”也有失蹄的时候,在使用拦截器对接口入参进行预先处理时,就发生了一个问题。


问题描述:

项目中有个拦截器,需要新拦截一个post请求的接口,并获取参数,对参数进行处理。因为是post请求,所以 request.getParamter(“data”)是获取不到的,只能通过 request.getInputStream来获取。获取源码如下:

public String getParam(HttpServletRequest request) throws IOException {
        BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
        StringBuilder sb = new StringBuilder();
        String inputStr;
        while ((inputStr = streamReader.readLine()) != null) {
            sb.append(inputStr);
        }
        System.out.println(sb.toString());
        return sb.toString();
    }

入参也获取到了,拦截代码也写好了,一运行,却发现接口调不通了,,提示如下

{
“timestamp”: “2021-07-21T06:31:44.888+0000”,
“status”: 400,
“error”: “Bad Request”,
“message”: “Required request body is missing:xxxxxxx”,
“path”: “/xxxxx”
}

发现问题后很奇怪,为什么原先好好的代码不同了(遇到问题来网上找答案的小伙伴可能跟我是一模一样的心情),冲完浪才发现,我在接收参数的时候使用了 @RequestBody 这个注解,而这个注解其实也是使用 getInputStream 这个方法来获取参数的,重点是!! getInputStream 不像 getParamter 能取多次,getInputStream 在取完值后,流就用掉了,第二次再取得时候, 这个流就是空的了。(想想也对,流这个东西本来就是瞬时的,怎么可能来回的去用呢)。


解决方案:

既然想在拦截器和controller代码中都要获取参数,那么就得改造一下原来的使用方式。拦截器获取参数方法中,只加了一行代码

request.setAttribute(“body”,sb.toString());

把获取到的参数再放入request中缓存一下,这个方法就算是改造完毕

public String getParam(HttpServletRequest request) throws IOException {
        BufferedReader streamReader = new BufferedReader( new InputStreamReader(request.getInputStream(), "UTF-8"));
        StringBuilder sb = new StringBuilder();
        String inputStr;
        while ((inputStr = streamReader.readLine()) != null) {
            sb.append(inputStr);
        }
        System.out.println(sb.toString());
        // post请求的接口在从 inputStream中读取参数后,控制层使用@RequestBody会报请求体为空的异常,
        // 在这里用attribute缓存一下,同样接口也要使用attribute来接收
        request.setAttribute("body",sb.toString());
        return sb.toString();
    }

接口代码也需要改造一下。

    @RequestMapping(value = "/xxxxx",method = RequestMethod.POST)
    public BaseResp doSomething(HttpServletRequest request){
        BaseResp resp= new BaseResp();
        Gson gson = new Gson();
        try {
            String body = String.valueOf(request.getAttribute("body"));
            RequestBean requestBean = gson.fromJson(body,RequestBean.class);
            resp= service.doSomething(requestBean);
        } catch (Exception e) {
            log.error("【doSomething 异常】","",e);
        }
        return response;
    }

接口入参就不能再使用@RequestBody了,而是要使用HttpServletRequest,然后再通过 request.getAttribute 方法来获取我们在拦截器方法中存放的参数,再通过Gson(用的是谷歌的Gson)转换一下,转成我们的入参对象,就可以正常使用了。


总结:

其实还是不了解 @RequestBody 的源码,和没有发现流使用一次会没得特点,才导致出这么一个问题,不过后续此类问题也不会再犯了,也要认真接着学习鸭

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值