在开发spring项目过程中,小编遇到了 Required request body is missing 的错误。经过搜索查询,才知道这个spring开发中大多数人遇到的常见问题之一。

Required request body is missing原因

这个问题原因是 Controller 没有取到数据,小编用的是 @RequestBody 来获取数据,原来是 request.getInputStream() 只能被读取一次。在前置拦截 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { 中已经读取过数据一次来进行相关的判断,所以在Controller层中再次读取的就为空了。

解决方法:

在自定义的请求对象中,将获取请求的输入对象流用一个变量保存起来,然后在生成一个新的请求对象即可。相关代码如下:

import org.springframework.util.StreamUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;

public class RequestWrapper extends HttpServletRequestWrapper {

    /**
     * 用于将流保存下来
     */
    private byte[] requestBody;

    public RequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        requestBody = StreamUtils.copyToByteArray(request.getInputStream());
    }

    @Override
    public ServletInputStream getInputStream() {
        final ByteArrayInputStream bais = new ByteArrayInputStream(requestBody);
        return new ServletInputStream() {
            @Override
            public int read(){
                return bais.read();  // 读取 requestBody 中的数据
            }
            @Override
            public boolean isFinished() {
                return false;
            }
            @Override
            public boolean isReady() {
                return false;
            }
            @Override
            public void setReadListener(ReadListener readListener) { }
        };
    }

    @Override
    public BufferedReader getReader() {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }
}

在过滤器中处理

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
 * 在 Filter 中添加一个新的请求对象
 */
@WebFilter(urlPatterns={"/*"},filterName = "apiValidateFilter")
public class ApiValidateFilter implements Filter {

    @Override
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        ServletRequest requestWrapper = null;
        if(request instanceof HttpServletRequest) {
            requestWrapper = new RequestWrapper((HttpServletRequest) request);
        }
        if(requestWrapper == null) {
            chain.doFilter(request, response);
        } else {
            chain.doFilter(requestWrapper, response);
        }
    }
    @Override
    public void init(FilterConfig arg0) throws ServletException {}
}