最近在开发中遇到了一个需求,需要重复读取HttpServletRequest
请求内容及设置自定义header向下传递,但是会出现Required request body is missing
,原因是ServletInputStream
的流只能读取一次,那么我们只需要让请求内容可以重复读取即可,可以通过HttpServletRequestWrapper
来实现。
MutableHttpServletRequest
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() throws IOException { return new BufferedReader(new InputStreamReader(getInputStream(), StandardCharsets.UTF_8)); } @Override public ServletInputStream getInputStream() throws IOException { if (bytes == null) { bytes = new byte[0]; } final ByteArrayInputStream bais = new ByteArrayInputStream(bytes); return new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return bais.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() { 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); } return Collections.enumeration(set); } } 复制代码
MutableHttpServletRequest
使用创建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() { // do nothing } } 复制代码
注册filtel
@Bean public FilterRegistrationBean<BodyReaderFilter> Filters() { FilterRegistrationBean<ReadRequestBodyFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new ReadRequestBodyFilter()); registrationBean.addUrlPatterns("/*"); registrationBean.setName("readRequestBody-filter"); registrationBean.setOrder(1); return registrationBean; } 复制代码
http
请求内容只能被读取一次,如果您在过滤器中读取body
,则目标servlet
将无法重新读取它,这也会导致IllegalStateException
。 使用上面给定的HttpServletRequestWrapper
,就可以读取HTTP请求正文,然后Servlet以后仍可以读取它。 本质上,请求主体内容被缓存在包装对象中,因此在整个请求生命周期中,它可以是N次。
httpServletRequest中的流只能读取一次的原因