我正在尝试解析 RequestMapping
方法的某些特定参数,以从请求正文中提取值并验证它们并将它们注入(inject)某些带注释的参数中。
@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
(get from NativeWebRequest
) 无法读取输入流(有些参数在请求体中)超过一次。那么如何多次检索 Inputstream
/Reader
或请求正文?
最佳答案
您可以添加一个过滤器,拦截当前的 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);
}
}
经过这个过滤器后,大家会看到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
的实现可以看ContentCachingRequestWrapper
来自 spring 框架,它基本上做同样的事情。
这种方法有其自身的缺点。首先,它的效率有点低,因为对于每个请求,请求正文至少被读取两次。另一个重要的缺点是,如果您的请求正文包含值(value) 10 GB
的流,您会读取该 10 GB
数据,更糟糕的是会将其放入内存以供进一步检查。
关于java - 如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34804205/