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