背景
由于在SpringBoot过滤器或者拦截器中,request中getReader()和getInputStream()只能调用一次,到controller里数据就为空了,因此会导致Controller中@RequestBody的参数无法注入而导致 400 错误
解决方案
写HttpServletRequestWrapper把request保存下来,然后通过过滤器把保存下来的request再填充进去
1. 写一个CxmHttpServletRequestWrapper包装类,继承HttpServletRequestWrapper
@Component
public class CxmHttpServletRequestWrapper extends HttpServletRequestWrapper {
private byte[] requestBody = new byte[0];
private boolean bufferFilled = false;
private ConcurrentHashMap<String, String> cxmHeaders = new ConcurrentHashMap<>();
public CxmHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new CachedServletInputStream(getRequestBody());
}
@Override
public String getHeader(String name) {
String headerValue = cxmHeaders.get(name);
if (headerValue != null) {
return headerValue;
} else {
return super.getHeader(name);
}
}
public void setHeader(String name, String value){
this.cxmHeaders.put(name, value);
}
public byte[] getRequestBody() throws IOException {
if (bufferFilled) {
return Arrays.copyOf(requestBody, requestBody.length);
}
InputStream inputStream = super.getInputStream();
requestBody = IOUtils.toByteArray(inputStream);
bufferFilled = true;
return requestBody;
}
}
写一个CachedServletInputStream继承ServletInputStream用来处理数据
public class CachedServletInputStream extends ServletInputStream {
private ByteArrayInputStream buffer;
public CachedServletInputStream(byte[] contents) {
this.buffer = new ByteArrayInputStream(contents);
}
@Override
public int read() throws IOException {
return buffer.read();
}
@Override
public boolean isFinished() {
return buffer.available() == 0;
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setReadListener(ReadListener listener) {
throw new RuntimeException("Not implemented");
}
}
2. 在过滤器中取值的时候转换成为我们自己的request包装类,并且把request传递下去
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest requestWrapper = null;
if (request instanceof HttpServletRequest) {
requestWrapper = new CxmHttpServletRequestWrapper((HttpServletRequest) request);
}
chain.doFilter(requestWrapper, response);
}
3. 过滤器配置
@Slf4j
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
/**
*
* @Title: Filters
* @Description: 配置自定义的filter
* @return
* @throws
*
*/
@Bean
public FilterRegistrationBean<CxmRequestValidFilter> Filters() {
FilterRegistrationBean<CxmRequestValidFilter> register = new FilterRegistrationBean<CxmRequestValidFilter>();
register.setFilter(new CxmRequestValidFilter());
register.addUrlPatterns("/*");
// 初始化filter的参数
register.addInitParameter("profile", profile);
register.setName("cxmRequestValidFilter");
return register;
}
}