所需的请求正文在使用 ContentCachingRequestWrapper 后丢失。

huangapple go评论91阅读模式
英文:

Required request body is missing after using ContentCachingRequestWrapper

问题

我需要在我的 GenericFilterBean 中读取请求有效负载。
由于我不能调用 getReader 两次,所以我使用了 ContentCachingRequestWrapper,如下所示-

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:由处理程序执行引起的已解析异常:org.springframework.http.converter.HttpMessageNotReadableException:缺少所需的请求体: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

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

谢谢。

英文:

I need to read the request payload in one of my GenericFilterBean.
Beacuse I cannot call getreader twice I used ContentCachingRequestWrapper like-

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

Getting the request body-

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

And chaining the request-

chain.doFilter(cachedRequest, response);

But still my controller throws-

 .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 ideas on how to chain the request so I can read the payload in the controller as well?

Thank you.

答案1

得分: 6

我也面临了同样的问题。您需要在请求包装器(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);

        // 这一行是必要的,用于缓存InputStream
        wrappedRequest.getInputStream();
        // 使用下面这行,您可以将requestBody映射为String
        // String requestBody = IOUtils.toString(wrappedRequest.getInputStream(), StandardCharsets.UTF_8);

        chain.doFilter(wrappedRequest, servletResponse);
    }
}

控制器(Controller)部分:

@PostMapping(ENDPOINT)
void endpoint(HttpServletRequest request) {
    ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
    String requestBody = new String(requestWrapper.getContentAsByteArray());
    // 处理requestBody
}
英文:

I faced same issue. You need to call getInputStream on requestWrapper in order to let it be cached. This is how your filter should look like:

@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);
    }
}

Controller:

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

答案2

得分: 0

我认为通过以下方式进行操作:

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

是错误的方法。

尝试这样做:

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

正如文档所建议的:

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

一些有用的链接:
链接1链接2

英文:

I think by doing this :

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

you are doing it wrong.

Try this :

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

As the documentation suggests:

> caches all content read from the input stream and reader, and allows this content to be retrieved via a byte array

Some helpful links:
Link 1, Link 2.

huangapple
  • 本文由 发表于 2020年9月8日 18:17:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/63791808.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定