Required request body is missing-请求接口报错
一、问题由来
自己目前在做一个小程序的后台,已经写好了项目中的很多的接口,同时也在进行一些修改,比如添加拦截器,统一校验一个固定的参数是否正确。
在自己添加拦截器之前,这些接口都可以正常访问,可是在添加拦截器之后,再次访问接口就出现异常,异常信息为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() {
}
}
参考文章
https://blog.csdn.net/m0_37542889/article/details/82889617
https://zhuanlan.zhihu.com/p/239948869
https://www.jb51.net/article/193961.htm