SpringMVC中重复读取request中的请求体

315 阅读2分钟

1.方法一:使用SpringMVC提供的ContentCachingRequestWrapper包装请求

自定义一个Filter

public class CachingRequestBodyFilter extends GenericFilterBean {
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest currentRequest = (HttpServletRequest) request;
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
        chain.doFilter(wrappedRequest, response);
    }
}

把Filter注册到Servlet容器中

@Configuration
public class CachingRequestBodyFilterConfig {
​
    @Bean
    public FilterRegistrationBean<CachingRequestBodyFilter> filterRegistration() {
        FilterRegistrationBean<CachingRequestBodyFilter> registration = new FilterRegistrationBean<>(new CachingRequestBodyFilter());
        registration.setOrder(2);
        return registration;
    }
}

读取请求体中的内容:

ContentCachingRequestWrapper nativeRequest = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
byte[] contentAsByteArray = nativeRequest.getContentAsByteArray();
String s = new String(contentAsByteArray);
System.out.println(s);

2.方法二

思路很简单:第一步,读取HttpServletRequest的字节流的数据,保存到一个字节数组bytes;第二步,重写getInputStream()方法和getReader()方法,让这两个方法都从字节数组bytes中读取数据,返回给调用者;第三步,写个过滤器,让HTTP请求一进入系统,就执行第一步和第二步,然后后面都用重写的HttpServletRequest对象。这样,就可以重复读取HttpServletRequest携带的HTTP请求体数据了。

public class RepeatableHttpServletRequest extends HttpServletRequestWrapper {
    private final byte[] bytes;
    public RepeatableHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        //读取字节流数据到字节数组
        bytes = IOUtils.toByteArray(request.getInputStream());
    }
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //重写getInputStream()
        return new ServletInputStream() {
            private int lastIndexRetrieved = -1;
            private ReadListener readListener = null;
            @Override
            public boolean isFinished() {
                return (lastIndexRetrieved == bytes.length-1);
            }
            @Override
            public boolean isReady() {
                // This implementation will never block
                // We also never need to call the readListener from this method, as this method will never return false
                return isFinished();
            }
            @Override
            public void setReadListener(ReadListener readListener) {
                this.readListener = readListener;
                if (!isFinished()) {
                    try {
                        readListener.onDataAvailable();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                } else {
                    try {
                        readListener.onAllDataRead();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                }
            }
            @Override
            public int read() throws IOException {
                int i;
                if (!isFinished()) {
                    i = bytes[lastIndexRetrieved+1];
                    lastIndexRetrieved++;
                    if (isFinished() && (readListener != null)) {
                        try {
                            readListener.onAllDataRead();
                        } catch (IOException ex) {
                            readListener.onError(ex);
                            throw ex;
                        }
                    }
                    return i;
                } else {
                    return -1;
                }
            }
        };
    }
    //重写getReader()方法
    @Override
    public BufferedReader getReader() throws IOException {
        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
        BufferedReader temp = new BufferedReader(new InputStreamReader(is));
        return temp;
    }
}

封装过滤器:

public class CachingRequestBodyFilter extends GenericFilterBean {
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
        HttpServletRequest currentRequest = (HttpServletRequest) request;
        RepeatableHttpServletRequest wrappedRequest = new RepeatableHttpServletRequest(currentRequest);
        chain.doFilter(wrappedRequest, response);
    }
}

注册过滤器和方法一中相同

读取请求体中的内容:

ServletInputStream inputStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
​
int len;
while((len = inputStream.read(buffer)) != -1) {
    outSteam.write(buffer, 0, len);
}
String s = outSteam.toString();
System.out.println(s);