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. MutableHttpServletRequest
use
-
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
-
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