过滤器request参数中payload丢失问题
Java Spring 过滤器 request 参数中 payload 丢失问题
省流版:
org.springframework.boot:spring-boot:2.1.8.RELEASE && org.springframework:spring-web:5.1.9.RELEASE版本中的org.springframework.web.filter.HiddenHttpMethodFilter#doFilterInternal方法读取HttpServletRequest.InputStream流导致后续过滤器和拦截器无法再次读取InputStream。
起因:
最近有一个需要在前端对接口数据进行加密,再后端接口进行解密的需求,所以打算用rsa,前端请求数据公钥加密后,后端在拦截器中解密,而当前端请求到达后端自定义拦截器处时,读取出InputStream为空,只能通过request.getParameter取出对应的参数值,但是无法取出body中的数据,也就是即无法获取json数据
排查过程:
- (此步方向错误)首先,对上一级的过滤器进行排查,初步怀疑是上一级过滤器中的
request包装类代码逻辑错误,在包装过程中没有正确存储InputStream所以搭建了一个最小环境测试包装类(与发生问题的环境版本不同),发现在其他环境中包装类能正常重读InputStream数据。 - 再者,对项目中其他的过滤器进行屏蔽,发现并无效果,依然无法读取
InputStream数据。 - 通过
IDEA Debugger Frames逐个方法反推,逐步定位发现如果发起的是POST请求(GET请求也无法传递body)在org.springframework.web.filter.OncePerRequestFilter的子类中org.springframework.web.filter.HiddenHttpMethodFilter#doFilterInternal方法执行了request.getParameter(this.methodParam);导致InputStream数据丢失。
解决方案:
屏蔽
HiddenHttpMethodFilter过滤器,使其不能读取InputStream,但是可能存在一些安全性的问题a. 屏蔽方法有两种,第一种是通过代码配置,参考链接、参考代码如下。
1
2
3
4
5
6
7
8
9
public class FilterConfig {
public FilterRegistrationBean registration(HiddenHttpMethodFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
}
b. 通过配置关闭,在Spring boot2.1.0版本后可以通过配置关闭该过滤器,在2.2版本后默认关闭,屏蔽配置:spring.mvc.hiddenmethod.filter.enabled: false。通过转换为
ServletServerHttpRequest使用getBody方法获取body数据,代码如下。1
new String(StreamUtils.copyToByteArray(new ServletServerHttpRequest((HttpServletRequest) servletRequest).getBody()))
重新实现
HiddenHttpMethodFilter中的doFilterInternal方法,在读取之前将request进行包装(未实践)在
HiddenHttpMethodFilter调用之前将request进行包装(未实践)
参考:
- HiddenHttpMethodFilter consumes input stream of POST request
-
ServletServerHttpRequest.getBody - Disable auto-configuration of HiddenHttpMethodFilter by default
- Why is HttpServletRequest inputstream empty?