我们如何在 Spring Boot Filter 中获取和设置响应体

Posted

技术标签:

【中文标题】我们如何在 Spring Boot Filter 中获取和设置响应体【英文标题】:How can we get and set response body in Spring Boot Filter 【发布时间】:2020-11-09 04:07:29 【问题描述】:

我有一个 Spring MVC 应用程序,它返回 ResponseEntity 和 clientResponse 对象作为响应体

@RestController
public class XxxController 

    public void ResponseEntity(ClientRequest clientRequest) 
         ...
         return ResponseEntity.ok(clientResponse);
    

但是我们如何在 Spring Boot Filter 中获取 clientResponse 对象或者设置一个新的 Response body 呢?

@Component
public class MyClassFilter implements Filter 


    @Override
    public void doFilter( HttpServletRequest req,  HttpServletResponse res, FilterChain chain) throws IOException, ServletException 
 
    

    @Override
    public void destroy() 

    @Override
    public void init(FilterConfig arg0) throws ServletException 


【问题讨论】:

【参考方案1】:

我不确定,但我认为你可以试试这个:

        HttpServletResponse res = (HttpServletResponse) response;
        ContentCachingResponseWrapper ccrw= new ContentCachingResponseWrapper(res);
        //old body:
        String content=new String(ccrw.getContentAsByteArray(), "utf-8");
        //try this 
        HttpServletResponseWrapper hsrw=new HttpServletResponseWrapper(res);
        hsrw.getOutputStream().write(/*new body*/);
        //OR this 
        ServletResponseWrapper responseWrapper = (ServletResponseWrapper)response;
        responseWrapper.getResponse().resetBuffer();
        responseWrapper.getResponse().getOutputStream().write(/*new body*/);
        

【讨论】:

使用上面的ccrw可以做到ccrw.resetBuffer();ccrw.getOutputStream().write(<bytes>);crw.copyBodyToResponse();【参考方案2】:

不确定在过滤器中获取响应是什么意思。在过滤器中,请求尚未传递给控制器​​,因此还没有响应。你可以得到请求。但是请注意不要读取请求,因为在这种情况下,请求流将在过滤器中被读取,并且当它到达控制器时,整个请求流将已经被读取。要设置响应,您可以执行以下操作:

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException 
    response.resetBuffer();
    response.setStatus(HttpStatus.OK);
    response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
    response.getOutputStream().print(new ObjectMapper().writeValueAsString(myData));
    response.flushBuffer(); // marks response as committed -- if we don't do this the request will go through normally!

你可以在这里看到为什么你必须刷新响应。你也可以sendErrorHttpServletResponse#sendError How to change ContentType

如果您不刷新响应,您的请求将沿过滤器链继续(当然,您必须添加 chain.doFilter(request, response);!)。

【讨论】:

There is a response on the way out... "过滤器是一个对象,它对资源请求(servlet 或静态内容)或来自资源,或两者兼而有之。” - docs.oracle.com/javaee/6/api/javax/servlet/Filter.html

以上是关于我们如何在 Spring Boot Filter 中获取和设置响应体的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot 2 实战:如何自定义 Servlet Filter

Spring Boot使用嵌入式容器,自定义Filter如何配置?

Spring Boot 整合 Web 开发

Spring Boot参考教程Spring Boot配置Servlet,Filter,Listener,Interceptor

在 Spring boot 中为 Filter (OncePerRequestFilter) 编写单元测试

Spring Boot:考虑到用户角色,如何编写自定义 Pre Filter?