[英]Adding header in response in filter?
我需要在每個響應中添加標題。 我打算在下面做
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
filterChain.doFilter(request, response);
response.addHeader("Access-Control-Allow-Origin", "*");
}
}
我想在filterChain.doFilter(request, response)
做,這樣一旦控制器處理它,我只需在返回客戶端之前添加標頭。 這是正確的嗎 ?
但是根據如何編寫響應過濾器?
在
chain.doFilter
返回之后,對響應執行任何操作都為時已晚。 此時,整個響應已經發送到客戶端,您的代碼無法訪問它。
以上聲明在我看來並不正確。 我不能在filterChain.doFilter(request, response)
之后添加標頭嗎? 如果不是為什么?
我正在使用 spring mvc。
在filterChain.doFilter
之后,對響應執行任何操作都為時已晚。 此時,整個響應已經發送到客戶端。
您需要將包裝響應構建到您自己的類中,將這些包裝器傳遞給doFilter
方法並處理包裝器中的任何處理。
已經有一個響應包裝器:您可以擴展的HttpServletResponseWrapper
。 例如:
public class MyResponseRequestWrapper extends HttpServletResponseWrapper{
public MyResponseRequestWrapper(HttpServletResponse response) {
super(response);
}
}
您的過濾器:
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
HttpServletResponse myResponse = (HttpServletResponse) response;
MyResponseRequestWrapper responseWrapper = new MyResponseRequestWrapper(myResponse);
responseWrapper.addHeader("Access-Control-Allow-Origin", "*");
filterChain.doFilter(request, myResponse);
}
我在我的 Spring 3.0.x 項目中使用它:
public class MyFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
response.addHeader("headerName", "headerValue");
filterChain.doFilter(request, response);
}
}
工作正常。
修改響應的過濾器通常必須在響應返回給客戶端之前捕獲響應。 為此,您將一個替代流傳遞給生成響應的 servlet。 替代流可防止 servlet 在完成時關閉原始響應流,並允許過濾器修改 servlet 的響應。
為了將此替代流傳遞給 servlet,過濾器會創建一個響應包裝器,該包裝器覆蓋 getWriter 或 getOutputStream 方法以返回此替代流。 包裝器被傳遞給過濾器鏈的 doFilter 方法。 包裝方法默認調用包裝的請求或響應對象。 這種方法遵循設計模式中描述的著名的包裝器或裝飾器模式,
這有點晚了,但下面的內容可能會有所幫助所以如果您真的想將值附加到現有標頭,或向現有標頭添加新值,那么最好的方法是編寫包裝器並在包裝器中設置值。
然后在過濾器中鏈接響應
HttpServletResponse response = (HttpServletResponse) servletResponse;
ByteArrayPrinter pw = new ByteArrayPrinter();
// Create a wrapper
HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
@Override
public void setContentType(final String type) {
super.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
@Override
public PrintWriter getWriter() {
return pw.getWriter();
}
// set the outputstream content type to JSON
@Override
public ServletOutputStream getOutputStream() throws IOException {
ServletResponse response = this.getResponse();
String ct = (response != null) ? response.getContentType() : null;
if (ct != null && ct.contains(APPLICATION_XHTML)) {
response.setContentType(ct + AppConstants.CONSTANT_COMMA + MediaType.APPLICATION_JSON_UTF8_VALUE);
}
return pw.getStream();
}
};
chain.doFilter(httpRequest, wrappedResp);
這是 ByteArrayPrinter.java
public class ByteArrayPrinter {
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PrintWriter pw = new PrintWriter(baos);
private ServletOutputStream sos = new ByteArrayServletStream(baos);
public PrintWriter getWriter() {
return pw;
}
public ServletOutputStream getStream() {
return sos;
}
byte[] toByteArray() {
return baos.toByteArray();
}
}
這是 ByteArrayServletOutputStream
public class ByteArrayServletStream extends ServletOutputStream {
ByteArrayOutputStream baos;
ByteArrayServletStream(ByteArrayOutputStream baos) {
this.baos = baos;
}
@Override
public void write(int param) throws IOException {
baos.write(param);
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
// TODO Auto-generated method stub
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.