使用 ContentCachingRequestWrapper 后缺少所需的请求正文

Posted

技术标签:

【中文标题】使用 ContentCachingRequestWrapper 后缺少所需的请求正文【英文标题】:Required request body is missing after using ContentCachingRequestWrapper 【发布时间】:2020-12-26 17:10:29 【问题描述】:

我需要在我的GenericFilterBean 之一中读取请求有效负载。 因为我不能打电话给getreader twice 我用ContentCachingRequestWrapper like-

HttpServletRequest httpRequest = (HttpServletRequest) request;
ContentCachingRequestWrapper cachedRequest = new ContentCachingRequestWrapper(httpRequest);

获取请求正文-

String payload = cachedRequest.getReader().lines().collect(Collectors.joining());

并链接请求-

chain.doFilter(cachedRequest, response);

但我的控制器仍然抛出-

 .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by handler execution: org.springframework.http.converter.HttpMessageNotReadableException: Required request body is missing: public org.springframework.http.ResponseEntity<?> com.siemens.plm.it.sf.api.controllers.OrderController.createCCOrder(com.siemens.plm.it.de.ms.provisioning.model.sap.SapQuoteCreationArgument,javax.servlet.http.HttpServletRequest) throws java.lang.Exception

关于如何链接请求以便我也可以读取控制器中的有效负载的 Ant 想法?

谢谢。

【问题讨论】:

使用ContentCachingRequestWrapper,您无法多次读取正文。在本教程中有一个替代方案,希望对您有所帮助。 baeldung.com/spring-reading-httpservletrequest-multiple-times 【参考方案1】:

我遇到了同样的问题。您需要在 requestWrapper 上调用 getInputStream 以使其被缓存。这就是您的过滤器的外观:

@Component
public class CachingRequestBodyFilter extends GenericFilterBean 

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
            throws IOException, ServletException 
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper((HttpServletRequest) servletRequest);

        //this line is necessary to cache InputStream
        wrappedRequest.getInputStream();
        //String requestBody = IOUtils.toString(wrappedRequest.getInputStream(), StandardCharsets.UTF_8); with this line you can map requestBody to String


        chain.doFilter(wrappedRequest, servletResponse);
    

控制器:

@PostMapping(ENDPOINT)
    void endpoint(HttpServletRequest request) 
        ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
        String requestBody = new String(requestWrapper.getContentAsByteArray());
        //process requestBody

【讨论】:

【参考方案2】:

我认为这样做:

String payload = cachedRequest.getReader().lines().collect(Collectors.joining());

你做错了。

试试这个:

String input = ByteSource.wrap(cachedRequest.getContentAsByteArray())
    .asCharSource(StandardCharsets.UTF_8).read();

正如documentation 建议的那样:

缓存从输入流和阅读器读取的所有内容,并允许通过字节数组检索此内容

一些有用的链接: Link 1, Link 2.

【讨论】:

我有完全相同的问题,@Furquam Ahmed 的评论不起作用。

以上是关于使用 ContentCachingRequestWrapper 后缺少所需的请求正文的主要内容,如果未能解决你的问题,请参考以下文章

在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?

今目标使用教程 今目标任务使用篇

Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)