一、问题
项目中,已经写好了项目中的很多的接口,同时也在进行一些修改,比如添加拦截器,统一校验一个固定的参数是否正确。
在自己添加拦截器之前,这些接口都可以正常访问,可是在添加拦截器之后,再次访问接口就出现异常,异常信息为Required request body is missing;
让我有些疑惑,之前还好好的,怎么突然就访问报错了呢?这个错误简直莫名其妙,感觉毫无道理,可是问题却实实在在出现。
二、问题分析
对于出现的这个问题,我首先是把错误信息往百度里面进行搜索,出现各种各样的答案,可是都不是我遇到的问题的答案。当查看各种答案,查看得比较
多的时候,慢慢的理解了出现这个问题的原因。一开始我理解的是,使用注解的方式不对,看了很多篇博文之后才发现问题所在,才搞清楚问题在哪里。
出现这个问题的原因是java后台项目在处理请求时,如果是使用请求对象获取输入流的方式来获取请求参数,只能获取一次请求参数;当第二次获取参数
时就会出现问题,报标题中的错误。至此终于搞清楚问题的原因,request.getInputStream()只能调用一次,我已经在拦截器中调用一次,当再使用注解
@RequestBody的时候,底层也是调用getInputStream()方法,因此抛出异常。
三、解决方案
自己去百度里面查看了很多的答案,也尝试了很多的方案,反反复复的尝试,希望能够解决问题,最终找到一种解决方案。解决方式为给所有的请求都
使用自定义的请求对象,在过滤器中进行处理。在拦截器中同样也是使用自定义的请求对象,这样就可以解决这个问题。原理就是,在自定义的请求对象
中,将获取请求的输入对象流用一个变量保存起来,然后在生成一个新的请求对象即可,代码我已经粘贴在下面:
获取请求参数的方法
/* @Description: 抽取获取请求参数的方法 * @author: dengchao * @date: 2021/8/18 16:51 * @param: request 请求对象 * @return: String */ private String getLoginToken(HttpServletRequest request) throws IOException { HttpServletRequest requestWrapper = new BodyReaderWrapper(request); StringBuffer sb = new StringBuffer() ; InputStream is = requestWrapper.getInputStream(); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String s = "" ; while((s=br.readLine()) != null){ sb.append(s) ; } //获取请求参数示例 { "loginToken": "9a1cdf7a143047c8ad5eee87dbdfd24a", "userPhone":"15215426598", "msgType":1} String str = sb.toString(); JSONObject jsonObject = JSONObject.parseObject(str); String loginToken = jsonObject.getString("loginToken"); log.info("loginToken--->" + loginToken); return loginToken; } 自定义请求类
public class BodyReaderWrapper extends HttpServletRequestWrapper{ //用于将流保存下来 private byte[] requestBody; public BodyReaderWrapper(HttpServletRequest request) throws IOException { super(request); requestBody = StreamUtils.copyToByteArray(request.getInputStream()); } @Override public ServletInputStream getInputStream() throws IOException { final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody); return new ServletInputStream() { @Override public int read() throws IOException { return bais.read(); } @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } }; } @Override public BufferedReader getReader() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream())); } } 使用过滤器来处理所有的请求
@Component @WebFilter public class ReplaceStreamFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { BodyReaderWrapper bodyReaderWrapper = new BodyReaderWrapper((HttpServletRequest) request); chain.doFilter(bodyReaderWrapper, response); } @Override public void destroy() { } }