如何在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
,您读取请求正文并对其进行缓存,然后实现getInputStream
和getReader
以从缓存值中读取。 由于在包装请求后,缓存的值始终存在,您可以多次读取请求正文:
@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
数据,甚至更糟糕的是将其带入内存以供进一步检查。