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

时间:2016-01-15 04:02:09

标签: java spring spring-mvc

我正在尝试解析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;
}

最大的问题是,我发现HttpServletRequest(来自NativeWebRequest)无法读取输入流(某些参数位于请求正文中)多次 。那么如何多次检索Inputstream / Reader或请求正文?

1 个答案:

答案 0 :(得分:23)

您可以添加过滤器,拦截当前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);
    }
}

在此过滤器之后,每个人都会看到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数据,更糟糕的是将其带入内存以供进一步检查。