java - 如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?

标签 java spring spring-mvc

我正在尝试解析 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 中,您读取请求正文并将其缓存,然后实现 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的实现可以看ContentCachingRequestWrapper来自 spring 框架,它基本上做同样的事情。

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

关于java - 如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34804205/

相关文章:

java - 带有 Spring MVC 的多列 Spring Roo 脚手架

java - 检查原语是否已设置

java - 完全不知道为什么 eclipse 会给出这个错误

java - 从笛卡尔积中获取不同记录的算法

java - Spring Security中如何做LDAP认证和数据库授权?

java - Spring 3.1 : Non-XML equivalent of annotation-driven transaction management

java - 不支持使用 JPA 更新查询的 DML 操作

java - 有没有办法只从那些以数字开头后跟句点的元素中删除前导数字?

java - Hibernate Save 总是返回 0

java - Spring 非阻塞 Rest "Send and forget"