spring boot 处理 request body中重复消费
场景
- 验签取参数,取完之后下游需要两次从 request 中获取body数据
- 请求日志
解决方案
缓存 request body 数据,然后向下传递
RepeatableHttpRequestWrapper
public class RepeatableHttpRequestWrapper extends HttpServletRequestWrapper {
private byte[] body;
/**
* Constructs a request object wrapping the given request.
*
* @param request The request to wrap
* @throws IllegalArgumentException if the request is null
*/
public RepeatableHttpRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
this.body = StreamUtils.copyToByteArray(request.getInputStream());
}
@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() throws IOException {
ByteArrayInputStream bais = new ByteArrayInputStream(this.body);
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}
@Override
public int available() throws IOException {
return body.length;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener listener) {
}
@Override
public int read() throws IOException {
return bais.read();
}
};
}
}
RepeatableFilter
public class RepeatableFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
if (request instanceof HttpServletRequest && StringUtils.startsWithIgnoreCase(request.getContentType(),
MediaType.APPLICATION_JSON_VALUE)) {
ServletRequest wrapper = new RepeatableHttpRequestWrapper((HttpServletRequest) request);
chain.doFilter(wrapper, response);
return;
}
chain.doFilter(request, response);
}
}
配置
@Configuration
public class MvcConfig {
@Bean
public FilterRegistrationBean someFilterRegistration()
{
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new RepeatableFilter());
registration.addUrlPatterns("/*");
registration.setName("repeatableFilter");
registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
return registration;
}
}
测试
@RestController
public class HelloController {
@Autowired
private ObjectMapper objectMapper;
@PostMapping("user")
public String hello(@RequestBody User user, HttpServletRequest request) throws JsonProcessingException {
System.out.println(objectMapper.writeValueAsString(user));
String body = getBody(request);
System.out.println("from request body: " + body);
return "success";
}
static public String getBody(HttpServletRequest request) {
try {
ServletInputStream in = request.getInputStream();
String body;
body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
return body;
} catch (IOException e) {
e.printStackTrace();
return "";
}
}
}
结果:
{"name":"aaa","age":23}
from request body: {
"name": "aaa",
"age": 23
}