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

时间:2019-03-29 18:29:37

标签: java servlet-filters

我正在开发一个带有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

2 个答案:

答案 0 :(得分:0)

文档说明ResponseEntity#ok返回HTTP OK(https://httpstatuses.com/200)状态代码。筛选器较早运行,因此稍后将覆盖状态。

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

答案 1 :(得分:0)

使用/string端点,您无需修改​​状态代码。使用/entity端点,您可以明确地知道(通过返回OK将其设置为200)。

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

因此,您需要 servlet /控制器完成其操作后更改响应代码。

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

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

但是不幸的是,这也不起作用!根据{{​​3}}:

  

请注意,postHandle与@ResponseBody和   为其编写和提交响应的ResponseEntity方法   在HandlerAdapter中和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;
    }

}