preface

Recently in development, I encountered a need to repeatedly read the HttpServletRequest request and set custom headers to pass down. However, Required request body is missing, the reason is that the stream of ServletInputStream can only be read once, so we only need to make the request content can be read repeatedly. Can be done by HttpServletRequestWrapper.

Implementation steps

1. The customMutableHttpServletRequest
public class MutableHttpServletRequest extends HttpServletRequestWrapper {
    private final String body;
    private byte[] bytes;
    private final Map<String, String> customHeaders;

    public MutableHttpServletRequest(HttpServletRequest request) throws IOException {
        super(request);
        this.customHeaders = new HashMap<String, String>();
        this.bytes = StreamUtils.copyToByteArray(request.getInputStream());
        this.body = new String(this.bytes, StandardCharsets.UTF_8);
    }

    public void putHeader(String name, String value) {
        this.customHeaders.put(name, value);
    }

    @Override
    public BufferedReader getReader(a) throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8));
    }

    @Override
    public ServletInputStream getInputStream(a) throws IOException {
        if (bytes == null) {
            bytes = new byte[0];
        }
        final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
        return new ServletInputStream() {
            @Override
            public boolean isFinished(a) {
                return false;
            }

            @Override
            public boolean isReady(a) {
                return false;
            }

            @Override
            public void setReadListener(ReadListener readListener) {}@Override
            public int read(a) throws IOException {
                returnbais.read(); }}; }@Override
    public String getHeader(String name) {
        String headerValue = customHeaders.get(name);

        if(headerValue ! =null) {
            return headerValue;
        }
        return ((HttpServletRequest) getRequest()).getHeader(name);
    }

    @Override
    public Enumeration<String> getHeaderNames(a) {
        Set<String> set = new HashSet<String>(customHeaders.keySet());

        @SuppressWarnings("unchecked")
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
        while (e.hasMoreElements()) {
            String n = e.nextElement();
            set.add(n);
        }
        returnCollections.enumeration(set); }}Copy the code
2. MutableHttpServletRequestuse
  1. Create a filter

    public class ReadRequestBodyFilter implements Filter {
        
        @Override
        public void init(FilterConfig filterConfiguration) throws ServletException {
            // do nothing
        }
        
      	@Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
            request = new MutableHttpServletRequest((HttpServletRequest) request);
            // do nothing
            chain.doFilter(request, response);
        }
       
        @Override
        public void destroy(a) {
            // do nothing}}Copy the code
  2. Registered filtel

    @Bean
    public FilterRegistrationBean<BodyReaderFilter> Filters(a) {
        FilterRegistrationBean<ReadRequestBodyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new ReadRequestBodyFilter());
        registrationBean.addUrlPatterns("/ *");
        registrationBean.setName("readRequestBody-filter");
        registrationBean.setOrder(1);
        return registrationBean;
    }
    Copy the code

conclusion

HTTP request content can only be read once, and if you read the body in the filter, the target servlet will not be able to reread it, which also results in an IllegalStateException. Using the HttpServletRequestWrapper given above, can read the HTTP request body, then the Servlet can still read it later. Essentially, the request body content is cached in the wrapper object, so it can be N times over the lifetime of the request.

Refer to the article

HttpServletRequestWrapper

The reason why the stream in httpServletRequest can only be read once

read httpservletrequest twice