我正在开发一个带有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
使用/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;
}
}
正如文档所述,ResponseEntity#ok
返回HTTP OK(https://httpstatuses.com/200)状态代码。过滤器运行较早,因此稍后会覆盖状态。
你应该使用ResponseEntity
中描述的其他方法创建https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html。