Java 当控制器返回ResponseEntity时,如何在筛选器中设置响应状态代码?
我正在开发一个带有servlet过滤器的简单Spring引导应用程序,用于设置响应状态代码:Java 当控制器返回ResponseEntity时,如何在筛选器中设置响应状态代码?,java,servlet-filters,Java,Servlet Filters,我正在开发一个带有servlet过滤器的简单Spring引导应用程序,用于设置响应状态代码: @Component public class TestFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
@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);
}
若控制器返回一个字符串,则一切正常(状态为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
}
}
@RestController
公共类测试控制器{
@GetMapping(“/string”)
公共字符串testString(){
返回“OK”;//过滤器设置的状态码为201
}
}
@RestController
公共类测试控制器{
@GetMapping(“/entity”)
公共响应度测试响应度(){
return ResponseEntity.ok(“ok”);//状态代码为200
}
}
为什么过滤器在使用ResponseEntity时不更改状态代码
--
Github上的项目:正如文档中所述,
响应属性#ok
返回HTTP ok()状态代码。过滤器运行较早,因此状态稍后会被覆盖
您应该使用。中描述的其他方法创建
响应属性
,因为文档中说明响应属性#ok
返回HTTP ok()状态代码。过滤器运行较早,因此状态稍后会被覆盖
您应该使用中描述的其他方法创建
响应属性。使用/string
端点,您不会修改状态代码。对于/entity
端点,您明确地是(通过返回ok将其设置为200)
您的过滤器实现更改响应状态代码,然后继续运行过滤器链的其余部分。我们刚刚建立的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);
}
}
}
但不幸的是,这也行不通!根据报告:
请注意,postHandle对于@ResponseBody和
ResponseEntity为其编写和提交响应的方法
在HandlerAdapter内和postHandle前。那就意味着它太大了
延迟对响应进行任何更改,例如添加额外的
标题。对于此类场景,您可以实施ResponseBodyAdvice和
要么将其声明为控制器建议bean,要么对其进行配置
直接在RequestMappingHandlerAdapter上
这可能会达到您想要的效果(注意,我设置为“CHECKPOINT”只是为了演示这一点!)
@ControllerAdvice
公共类TestResponseBodyAdvice实现ResponseBodyAdvice{
@凌驾
公共布尔支持(MethodParameter returnType,Class>converterType){
返回true;
}
@凌驾
public T beforeBodyWrite(T body,MethodParameter returnType,MediaType selectedContentType,
类>selectedConverterType、ServerHttpRequest请求、ServerHttpResponse响应){
//
//在此处插入所选的状态代码
response.setStatusCode(HttpStatus.CHECKPOINT);
返回体;
}
}
使用/string
端点,您不会修改状态代码。对于/entity
端点,您明确地是(通过返回ok将其设置为200)
您的过滤器实现更改响应状态代码,然后继续运行过滤器链的其余部分。我们刚刚建立的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);
}
}
}
但不幸的是,这也行不通!根据报告:
请注意,postHandle对于@ResponseBody和
ResponseEntity为其编写和提交响应的方法
在HandlerAdapter内和postHandle前。那就意味着它太大了
延迟对响应进行任何更改,例如添加额外的
标题。对于此类场景,您可以实施ResponseBodyAdvice和
要么将其声明为控制器建议bean,要么对其进行配置
直接在RequestMappingHandlerAdapter上
这可能会达到您想要的效果(注意,我设置为“CHECKPOINT”只是为了演示这一点!)
@ControllerAdvice
公共类TestResponseBodyAdvice实现ResponseBodyAdvice{
@凌驾
公共布尔支持(MethodParameter returnType,Class>converterType){
返回true;
}
@凌驾
public T beforeBodyWrite(T body,MethodParameter returnType,MediaType selectedContentType,
类>selectedConverterType、ServerHttpRequest请求、ServerHttpResponse响应){
//
//在此处插入所选的状态代码
response.setStatusCode(HttpStatus.CHECKPOINT);
返回体;
}
}