Java 如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34804205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I read request body multiple times in Spring 'HandlerMethodArgumentResolver'?
提问by Kim
I'm trying to resolve some certain parameters of RequestMapping
methods, to extract values from request body and validates them and inject them into certain annotated parameters.
我正在尝试解析RequestMapping
方法的某些某些参数,从请求正文中提取值并验证它们并将它们注入某些带注释的参数中。
@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;
}
The biggest problem is that I find out that HttpServletRequest
(get from NativeWebRequest
) cannot read input stream(some parameters are in the request body) more than one time. So how can I retrieve Inputstream
/Reader
or the request body more than one time?
最大的问题是我发现HttpServletRequest
(get from NativeWebRequest
) 不能多次读取输入流(某些参数在请求正文中)。那么如何多次检索Inputstream
/Reader
或请求正文呢?
采纳答案by Ali Dehghani
You can add a filter, intercept the current HttpServletRequest
and wrap it in a custom HttpServletRequestWrapper
. In your custom HttpServletRequestWrapper
, you read the request body and cache it and then implement getInputStream
and getReader
to read from the cached value. Since after wrapping the request, the cached value is always present, you can read the request body multiple times:
您可以添加过滤器,拦截当前HttpServletRequest
并将其包装在自定义HttpServletRequestWrapper
. 在您的 custom 中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);
}
}
After this filter, everybody will see the wrappedRequest
which has the capability of being read multiple times:
在这个过滤器之后,大家会看到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
}
}
For implementing MultipleReadHttpRequest
, you can take a look at ContentCachingRequestWrapper
from spring framework which is basically does the same thing.
对于实现MultipleReadHttpRequest
,您可以ContentCachingRequestWrapper
从基本相同的 spring 框架中查看。
This approach has its own disadvantages. First of all, it's somewhat inefficient, since for every request, request body is being read at least two times. The other important drawback is if your request body contains 10 GB
worth of stream, you read that 10 GB
data and even worse bring that into memory for further examination.
这种方法有其自身的缺点。首先,它有点低效,因为对于每个请求,请求正文至少被读取两次。另一个重要的缺点是,如果您的请求正文包含10 GB
大量流,您将读取该10 GB
数据,更糟糕的是将其带入内存以供进一步检查。