如何在Spring’HandlerMethodArgumentResolver’中多次读取请求体?

我正在尝试解决RequestMapping方法的某些参数,从请求体中提取值并validation它们并将它们注入到某些带注释的参数中。

 @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 1, get corresponding input parameter from NativeWebRequest // 2, validate // 3, type convertion and assemble value to return return null; } 

最大的问题是我发现HttpServletRequest (从NativeWebRequest获取)无法读取输入流(某些参数在请求体中) NativeWebRequest 。 那么我怎样才能多次检索Inputstream / Reader或请求体呢?

您可以添加filter,拦截当前的HttpServletRequest并将其包装在自定义的HttpServletRequestWrapper 。 在您的自定义HttpServletRequestWrapper ,您读取请求正文并对其进行缓存,然后实现getInputStreamgetReader以从缓存值中读取。 由于在包装请求后,缓存的值始终存在,您可以多次读取请求正文:

 @Component public class CachingRequestBodyFilter extends GenericFilterBean { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { HttpServletRequest currentRequest = (HttpServletRequest) servletRequest; MultipleReadHttpRequest wrappedRequest = new MultipleReadHttpRequest(currentRequest); chain.doFilter(wrappedRequest, servletResponse); } } 

在此filter之后,每个人都将看到wrappedRequest ,它具有多次读取的能力:

 public class MultipleReadHttpRequest extends HttpServletRequestWrapper { private ByteArrayOutputStream cachedContent; public MultipleReadHttpRequest(HttpServletRequest request) throws IOException { // Read the request body and populate the cachedContent } @Override public ServletInputStream getInputStream() throws IOException { // Create input stream from cachedContent // and return it } @Override public BufferedReader getReader() throws IOException { // Create a reader from cachedContent // and return it } } 

为了实现MultipleReadHttpRequest ,您可以从spring框架看一下ContentCachingRequestWrapper ,它基本上做同样的事情。

这种方法有其自身的缺点。 首先,它效率有点低,因为对于每个请求,请求主体至少被读取两次。 另一个重要的缺点是,如果您的请求正文包含10 GB的流,您会读取10 GB数据,甚至更糟糕的是将其带入内存以供进一步检查。