如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文? [英] How can I read request body multiple times in Spring 'HandlerMethodArgumentResolver'?

查看:29
本文介绍了如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试解析 RequestMapping 方法的某些参数,从请求正文中提取值并验证它们并将它们注入某些带注释的参数中.

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.

@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 或请求体?

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 并将其包装在自定义的 HttpServletRequestWrapper 中.在您的自定义 HttpServletRequestWrapper 中,您读取请求正文并缓存它,然后实现 getInputStreamgetReader 以从缓存的值中读取.由于包装请求后,缓存的值始终存在,您可以多次读取请求正文:

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:

@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,它具有被多次读取的能力:

After this filter, everybody will see the wrappedRequest which has the capability of being read multiple times:

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 框架,基本上做同样的事情.

For implementing MultipleReadHttpRequest, you can take a look at ContentCachingRequestWrapper from spring framework which is basically does the same thing.

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

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.

这篇关于如何在 Spring 'HandlerMethodArgumentResolver' 中多次读取请求正文?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆