我想要做的是,在处理请求后为响应添加新标头。我需要检查已处理的HttpStatus
代码(在我的情况下是401未授权的)并添加新的标头。我知道Spring有拦截器,但无法按document:
请注意,HandlerInterceptor的postHandle方法并不总是非常适合与@ResponseBody和ResponseEntity方法一起使用。在这种情况下,HttpMessageConverter在调用postHandle之前写入并提交响应,这使得无法更改响应,例如添加标头。相反,应用程序可以实现ResponseBodyAdvice并将其声明为@ControllerAdvice bean或直接在RequestMappingHandlerAdapter上配置它。
好吧,我实施了ResponseBodyAdvice
。是的,它允许正文修改,但我无法修改标题,事件无法找到从控制器返回的状态代码。
使用servlet过滤器的另一个选项也不成功。我需要在filterChain.doFilter(servletRequest, servletResponse);
调用后添加标头。但它再次没有修改标头值。有没有办法完成这个简单的任务?
答案 0 :(得分:9)
听起来你正在使用servlet过滤器进入正确的轨道,你可能需要做的是将servlet响应对象包装起来,该对象检测到何时设置了401状态代码并添加了自定义标头那个时间:
HttpServletResponse wrappedResponse = new HttpServletResponseWrapper(response) {
public void setStatus(int code) {
super.setStatus(code);
if(code == 401) handle401();
}
// three similar methods for the other setStatus and the two
// versions of sendError
private void handle401() {
this.addHeader(...);
}
};
filterChain.doFilter(request, wrappedResponse);
答案 1 :(得分:3)
那么,Java会将HTTP响应显示为一个Object,您可以独立地更改不同的字段。
但是,服务器和客户端之间实际交换的是字节流和标题,并在正文之前发送。这就是为什么HttpResponse具有isCommitted()
方法的原因:在发送标头时提交响应。当然,一旦提交,您就不能再添加修改标头。一旦将足够的字符写入正文,servlet容器就可以提交并刷新响应。
因此,在处理完请求后,尝试更改标头是不安全的。它只有在未提交请求时才有效。安全的唯一情况是控制器本身不写响应并且只转发到视图。然后在postHandle
拦截器方法中,响应尚未提交,您可以更改标头。否则,您必须测试isCommitted()
,如果它返回true,则更改标题为时已晚!
当然,在这种情况下,拦截器和过滤器都无法做任何事情......
答案 2 :(得分:1)
如果不需要检查状态代码,那么你可以在preHandle方法上添加这些头文件(因为Spring在postHandle触发之前提交响应,所以在postHandle中添加它们对于从@ResponseBody标记的控制器方法返回的响应不起作用):
public class ControllerHandleInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler instanceof HandlerMethod) {
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setHeader("Expires", "0");
}
return true;
}
// other code...
}
答案 3 :(得分:0)
您可以实现ServletFilter并只包装原始响应对象。
这将允许您推迟实际写回复并添加自定义标题。
另一方面:这看起来有点像Spring Security Processing链。
答案 4 :(得分:0)
好吧,我实现了ResponseBodyAdvice。是的,它允许身体 修改,但我无法修改标题,事件 找不到从控制器返回的状态代码。
好吧,实际上,如果您将ServerHttpResponse
转换为ServletServerHttpResponse
,则可以。
(根据ServletServerHttpResponse
的调用方式,它必须为ResponseBodyAdvice
,您可以看到传递给ServerHttpResponse
的{{1}}实际上是{{1 }}在此method中。
因此只需实现一个ResponseBodyAdvice
,而无需再包装ServletServerHttpResponse
:
ResponseBodyAdvice