spring boot - 缓存请求之 ContentCachingRequestWrapper

ContentCachingRequestWrapper 是 spring boot 自带的请求体重复利用的工具,不过他也有缺点

That means if the request:

  • content is not consumed, then the content is not cached
  • and cannot be retrieved via {@link #getContentAsByteArray()}

也就是说,用ContentCachingRequestWrapper的前提:

  • 你要消费这个请求数据
  • 能过 getContentAsByteArray 方法获取缓存内容

如何使用呢?

CachingContentFilter

public class CachingContentFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        if (request instanceof HttpServletRequest) {
            if (request.getContentType() != null && !request.getContentType().contains(MediaType.MULTIPART_FORM_DATA_VALUE)) {
                ContentCachingRequestWrapper wrapper = new ContentCachingRequestWrapper((HttpServletRequest) request);
                //测试
                String requestBody = getRequestBody(wrapper);
                System.out.println("repeat:" + requestBody);
                chain.doFilter(wrapper, response);
                return;
            }
        }
        chain.doFilter(request, response);
    }

    private String getRequestBody(HttpServletRequest request) {
        String requestBody = "";
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            try {
                requestBody = IOUtils.toString(wrapper.getContentAsByteArray(), wrapper.getCharacterEncoding());
            } catch (IOException e) {
            }
        }
        return requestBody;
    }

}

配置

@Bean
public FilterRegistrationBean someFilterRegistration() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new CachingContentFilter());
    registration.addUrlPatterns("/*");
    registration.setName("cacheRequestFilter");
    registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
    return registration;
}

测试:

@PostMapping("/form1")
public String post1(HttpServletRequest request, @RequestBody String body) throws IOException {
    System.out.println("param: " + request.getParameter("name"));
    String s1 = new String(StreamUtils.copyToByteArray(request.getInputStream()));
    String s2 = new String(StreamUtils.copyToByteArray(request.getInputStream()));
    System.out.println("s1: " + s1);
    System.out.println("s2" + s2);
    ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
    String s3 = new String(wrapper.getContentAsByteArray(), "UTF-8");
    String s4 = new String(wrapper.getContentAsByteArray(), "UTF-8");
    System.out.println("s3: " + s3);
    System.out.println("s4" + s4);
    return "success";
}

结果:

s1: 
s2
s3: {
    "a":1
}
s4{
    "a":1
}

首先通过 @RequestBody 消费了请求体,再次使用 getContentAsByteArray 方式重复利用

点击阅读全文
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐