2015-06-08 40 views
6

我想要做的就是處理後,該請求被處理後添加一個新的頭到響應。我需要檢查處理的HttpStatus代碼(在我的情況下是401未授權)並添加一個新的標題。我知道春天有攔截器,但在document規定的反應不能被修改:春天 - 修改爲每個請求標題(的postHandle)

注意的HandlerInterceptor的的postHandle方法並不總是非常適用於和@ResponseBody方法ResponseEntity使用。在這種情況下,HttpMessageConverter會在調用postHandle之前寫入並提交響應,從而無法更改響應,例如添加標題。相反,應用程序可以實現ResponseBodyAdvice,並將其聲明爲@ControllerAdvice bean或直接在RequestMappingHandlerAdapter上進行配置。

那麼,我實施了ResponseBodyAdvice。是的,它允許正文修改,但我無法管理修改標題,事件找不到控制器返回的狀態代碼。

使用servlet過濾器的其他選項也不成功。我需要在filterChain.doFilter(servletRequest, servletResponse);調用後添加標題。但它再次不會修改標題值。有沒有辦法完成這個簡單的任務?

+0

你說的是servlet過濾器。你在哪裏添加了過濾器?你能否快速檢查http://stackoverflow.com/a/16191770/2231632是否適合你? – prabugp

+0

我試過了。我在'filterChain.doChain()'之後添加頭部,因爲在鏈完成後我需要狀態碼信息。它不起作用,Spring提交響應並且不允許修改過濾器。 – mtyurt

+0

這不是任何與spring有關的東西,但是隻要響應已經(部分)發送給客戶端,就不會再修改頭信息。您只能在此之前更改它。但我認爲你自己回來了401,那麼爲什麼不在這個位置簡單地做? –

回答

7

聽起來好像你是在正確的軌道與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); 
+0

您還必須重寫'sendError'方法和其他(不推薦)'' setStatus'消息。只是爲了確保alla案件被捕獲。 –

+0

工作正常,謝謝! – mtyurt

+0

@ M.Denium確實如我在代碼中的評論中所表明的那樣。這些方法的實施留給讀者練習... –

0

你可以實現一個ServletFilter,並只包裝原始的響應對象。

這將允許您推遲響應的實際寫作和添加自定義標題。

在另一方面:這看起來有點像Spring Security的處理鏈。

+0

你有任何包裝響應對象的例子嗎? – mtyurt

+0

正如Ian Roberts所述:http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletResponseWrapper.html – cbeutenmueller

2

那麼,Java顯示HTTP響應作爲一個對象,您可以獨立地更改不同的字段。

但是服務器和客戶端之間實際交換的是一個字節流,並且在主體之前發送了標頭併發送了。這就是爲什麼HttpResponse具有isCommitted()方法的原因:響應是在發送頭時提交的。當然,一旦提交,您就不能再添加修改標題。並且servlet容器可以提交併刷新響應一次足夠的字符已寫入正文。

所以試圖改變頭請求已被處理之後是不安全的。它只有在沒有提交請求的情況下才能工作。唯一安全的情況是控制器不會自己寫響應,而只是轉發到視圖。然後在postHandle攔截器方法中,響應尚未提交,並且您可以更改標題。否則,您必須測試isCommitted(),如果它返回true ...那麼更改標題爲時已晚!

當然,在那種情況下,既沒有攔截也不是一個過濾器可以做什麼...

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... 
}