当控制器返回ResponseEntity时,如何在Filter中设置响应状态代码?

问题描述 投票:0回答:2

我正在开发一个带有servlet过滤器的简单Spring Boot应用程序,用于设置响应状态代码:

@Component
public class TestFilter implements Filter {

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

        HttpServletResponse response = (HttpServletResponse) resp;
        response.setStatus(201);
        chain.doFilter(req, resp);
    }

如果控制器返回一个String,那么一切都按预期进行(状态为201)。但是如果控制器返回一个ResponseEntity,那么在调用doFilter()之后,状态代码是200而不是201:

@RestController
public class TestController {

    @GetMapping("/string")
    public String testString() {
        return "OK"; // status code is 201 as set by Filter
    }
}

@RestController
public class TestController {

    @GetMapping("/entity")
    public ResponseEntity<String> testResponseEntity() {
        return ResponseEntity.ok("OK"); // status code is 200
    }
}

使用ResponseEntity时为什么过滤器不会更改状态代码?

--

Github上的项目:https://github.com/timofeev-denis/set-status-code

java servlet-filters
2个回答
0
投票

使用/string端点,您不会修改状态代码。使用/entity端点,你明确地(你通过返回ok将它设置为200)。

您的过滤器实现会更改响应状态代码,然后继续运行过滤器链的其余部分 - 和then the servlet。我们刚刚建立了servlet(你的控制器)将响应状态代码设置为其他东西。

所以你需要在servlet / controller完成它之后更改响应代码。

您的第一个想法可能是重新实现您的过滤器,如下所示:

@Component
public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        try {
            chain.doFilter(req, resp);
        } finally {
            HttpServletResponse response = (HttpServletResponse) resp;

            response.setStatus(205);
        }
    }
}

但不幸的是,这也行不通!根据documentation

请注意,对于在HandlerAdapter中和在postHandle之前编写和提交响应的@ResponseBody和ResponseEntity方法,postHandle不太有用。这意味着对响应进行任何更改都为时已晚,例如添加额外的标头。对于此类方案,您可以实现ResponseBodyAdvice并将其声明为Controller Advice bean或直接在RequestMappingHandlerAdapter上进行配置。

这可能会产生你想要的效果(注意我设置为“CHECKPOINT”只是为了证明这一点!):

@ControllerAdvice
public class TestResponseBodyAdvice<T> implements ResponseBodyAdvice<T> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public T beforeBodyWrite(T body, MethodParameter returnType, MediaType selectedContentType,
            Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        //
        // insert status code of choice here
        response.setStatusCode(HttpStatus.CHECKPOINT);

        return body;
    }

}

0
投票

正如文档所述,ResponseEntity#ok返回HTTP OK(https://httpstatuses.com/200)状态代码。过滤器运行较早,因此稍后会覆盖状态。

你应该使用ResponseEntity中描述的其他方法创建https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html

© www.soinside.com 2019 - 2024. All rights reserved.