前言
最近在开发中遇到了一个需求,需要重复读取HttpServletRequest
请求内容及设置自定义header向下传递,但是会出现Required request body is missing
,原因是ServletInputStream
的流只能读取一次,那么我们只需要让请求内容可以重复读取即可,可以通过HttpServletRequestWrapper
来实现。
实现步骤
1.自定义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);
}
}
复制代码
2. 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次。