2012-11-19 47 views
8

我正在嘗試創建一個Java「過濾器」,它檢測自定義HTTP請求標頭並插入響應標頭,以便該文件自動下載。最重要的響應頭是「Content-Type = Attachment」響應頭。我已經創建了插入自定義首部的HTTP請求對象:Java過濾器無法設置響應標頭

function myHttpObject(filePath){ 
function makeHttpObject() { 
    return new XMLHttpRequest(); 
} 

var request = makeHttpObject(); 

request.open("GET", filePath, false); 
request.setRequestHeader("X-Wria-Download", "PDFdownload"); 
request.send(null); 
window.open(filePath); 
console.log(request.getAllResponseHeaders()); 
} 

這將插入的X Wria-下載報頭插入到所述請求。 然後我有一個Java過濾器,其將查找請求報頭和應設置響應頭爲「內容類型=附件」

import javax.servlet.*; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import javax.servlet.http.HttpSession; 
import java.io.IOException; 
import java.util.HashMap; 
import java.util.Map; 
public class Contenttypefilter implements Filter { 

protected FilterConfig filterConfig; 

public void init(FilterConfig filterConfig) throws ServletException { 
    this.filterConfig = filterConfig; 
} 

public void destroy() { 
    //noop 
} 

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 

    HttpServletRequest req = (HttpServletRequest) request; 
    HttpServletResponse res = (HttpServletResponse) response; 

    //get the headers we placed in the request 
    //based on those request headers, set some response headers 

    if(req.getHeader("X-Wria-Download") != null){ 
     res.setHeader("Content-Type", "application/pdf"); 
     res.setHeader("Content-Disposition", "attachment; filename=success.pdf"); 
    } 

    chain.doFilter(req,res); 
} 


} 

然後當然web.xml中具有代碼在包括過濾器所有的jsp文件。

讓我感到困惑的是,頭文件被設置在響應文件中,但它並沒有像應該那樣下載。如果我把res.setHeader(「Content-Disposition」,「attachment; filename = success.pdf」);在「if」語句之外,那麼它將起作用,但它會將下載行爲應用於我不想要的所有JSP。

爲什麼它在if語句中使用res.setHeader時應用內容處置,但不工作;然後在if語句之外工作?關於如何獲得所需行爲的任​​何想法(僅向我申請自定義請求標頭的jsp應用內容處置)?

+0

你肯定X- Wria-Download在Java中正確接收?您能否嘗試打印req.getHeader(「X-Wria-Download」)並查看它是否在Java過濾器中正確接收? –

+0

是的,它正確地接收它。在上面的「if」語句中:if(req.getHeader(「X-Wria-Download」)!= null){}它輸入語句,如果我放入一個System.out.println它將打印出該行。我也將Content-Disposition應用於文件,但Content-Type似乎在chain.Filter階段被覆蓋。儘管響應獲得了Content-Disposition,但它似乎並不像它那樣工作(不下載,而是將pdf作爲頁面提取。)我還看到了「X-Wria-Download」使用Chrome開發人員工具時的請求標題。 –

+0

奇怪如果: res.setHeader(「Content-Type」,「application/pdf」); res.setHeader(「Content-Disposition」,「attachment; filename = success.pdf」); 放在if語句之外,那麼過濾器將工作。這並不能解決我的問題,但是因爲我只想將過濾器應用於我附加了自定義標頭的servlet。 –

回答

0

試試這個:如果請求頭存在,請在請求中設置一個屬性。然後,檢查chain.doFilter(...)之後的屬性,然後設置響應標頭。

+0

好的,我試過這樣做。出於某種原因,在chain.doFilter之後,內容類型總是回覆到text/html。 –

0

問題是您的AjaxRequest(此處爲XMLHttpRequest)的標頭(X-Wria-Download)在服務過濾器之前未在您的HttpServletRequest對象中設置。

我認爲更好的想法將是使用專用的Servlet來處理您的ajax請求

+1

頭部(X-Wria-Download)實際上似乎在被傳遞給java濾鏡之前被應用到請求對象。當以調試模式瀏覽過濾器時,它會檢測到自定義請求頭,然後執行上面的if語句:if(req.getHeader(「X-Wria-Download」)!= null){}。 –

11

我認爲您的問題與您的Web Context的篩選器執行順序(即您的Web上下文中的某些篩選器)相關,在篩選器後執行並覆蓋標題。

Servlet的FilterChain of Responsibility模式

的實現,因此您可以嘗試:調用chain.doFilter後

  • 設置標題:

... 

chain.doFilter(req,res); 

HttpServletRequest req = (HttpServletRequest) request; 
HttpServletResponse res = (HttpServletResponse) response; 

//get the headers we placed in the request 
//based on those request headers, set some response headers 

if(req.getHeader("X-Wria-Download") != null){ 
    res.setHeader("Content-Type", "application/pdf"); 
    res.setHeader("Content-Disposition", "attachment; filename=success.pdf"); 
} 

這樣了servlet調用後,解釋如下,如果你的過濾器是第一個在web.xml中聲明,那麼setHeader代碼將是最後執行的代碼會被執行(見圖像如下)。

  • 請確保您的過濾器是執行Servlet後的最後一個執行過程,即它應該是第一個Servlet過濾器聲明解釋here

enter image description here

正如你可以看到過濾器1(首先在web.xml中聲明)是在servlet之前執行的第一個被執行,最後一個在servlet執行後執行。所以如果你想確定是Filter的最後一個設置,那麼將它聲明爲Filter1。

執行的順序由聲明的順序確定了部署描述符(web.xml):

servlet規範(第6.2.4節):

「的容器使用順序在構建過濾器鏈應爲 申請一個特定的請求URI如下:

「1。首先,在相同的 中匹配的過濾器映射爲了使這些元素出現在部署描述符中。

「2.接下來,在相同的 中匹配過濾器映射,以使這些元素出現在部署描述符中。」

所以要確定只是聲明它爲您的web.xml中的第一個過濾器。通過這種方式,它將成爲設置標題的最後一個過濾器。當然,如上所述,在調用chain.doFilter之後,在代碼中設置標題。

+1

謝謝!關鍵在於:1)確保你的過濾器是首先添加的,所以它會被最後調用,並且2)確保你在調用chain.doFilter(req,res)之後修改響應*之前,或者您的回覆可能會被覆蓋。 –

+0

不幸的是,這並沒有爲我使用Dropwizard 0.6/Jetty 8(我試圖修改cookie值。)由於某種原因,無論我添加'chain.doFilter()'調用,我的迴應回來與標題的原始值。我必須用另一種不太理想的方式解決我的問題,但如果其他人也有問題,我只是在評論這個答案。 – DuffJ

+0

感謝您的好評。我試圖用Jetty 9.2來做這樣的過濾器,但不幸的是它也沒有工作,似乎和@DuffJ有同樣的問題。在我的情況下,只有在我的'web.xml'中聲明它爲最後一個過濾器時,過濾器才能按預期工作。 – Sky

2

假設你使用這裏描述的響應包裝器,整個祕密就是何時在原始響應上調用getWriter()。這是因爲響應對象忽略了所有添加後,你問作家!

因此,請確保在添加所有標題之前調用getWriter()。 這是我推薦的doFilter()序列:

  1. 創建響應包裝

  2. chain.doFilter(origRequest,包裝器);

  3. 分配所有必需的頭到原來的(!)響應

  4. 得到原始響應

  5. 複製包裝的內容,筆者作家