web-dev-qa-db-ja.com

Javaフィルターが応答ヘッダーの設定に失敗しました

カスタムHTTPリクエストヘッダーを検出し、ファイルが自動的にダウンロードされるようにレスポンスヘッダーを挿入する、Java "Filter"を作成しようとしています。これにとって最も重要なレスポンスヘッダーは、 「Content-Type = Attachment」応答ヘッダー。カスタムヘッダーを挿入するHTTPリクエストオブジェクトを作成しました。

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-Downloadヘッダーがリクエストに挿入されます。次に、その要求ヘッダーを検索し、応答ヘッダーを「Content-Type = attachment」に設定する必要がある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があるのに、content-dispositionを適用しているのに、機能しないのはなぜですか。そして、それがifステートメントの外にあるときに動作しますか?目的の動作を実現する方法についてのアイデアはありますか(カスタムリクエストヘッダーを適用したjspにのみコンテンツ処理を適用します)?

11
Sol Slay

あなたの問題は、Web Contextの実行のフィルター順序に関連していると思います。つまり、Webコンテキスト内の一部のフィルターは、フィルターの後に実行され、ヘッダーをオーバーライドします。

サーブレット 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");
}

このようにして、サーブレットが呼び出された後にコードが実行され、以下で説明するように、フィルターがweb.xmlで最初に宣言された場合、setHeaderコードが最後に実行されます(下の画像を参照) )。

  • フィルタがサーブレットの実行後に最後に実行されることを確認してください。つまり、説明されているように宣言された最初のサーブレットフィルタである必要があります here

enter image description here

ご覧のとおり、Filter1(web.xmlで最初に宣言されたもの)は、サーブレットが実行される前に最初に実行され、サーブレットが実行された後に最後に実行されます。したがって、ヘッダーを設定する最後のフィルターであることを確認したい場合は、それをFilter1として宣言します。

実行の順序は、デプロイメント記述子(web.xml)での宣言の順序によって決定されます。

サーブレット仕様(セクション6.2.4):

「特定のリクエストURIに適用されるフィルターのチェーンを構築する際にコンテナーが使用する順序は次のとおりです。

"1.まず、これらの要素がデプロイメント記述子に表示されるのと同じ順序で一致するフィルターマッピング。

「2.次に、これらの要素がデプロイメント記述子に表示されるのと同じ順序で一致するフィルターマッピング。」

したがって、確実にweb.xmlの最初のフィルターとして宣言するだけです。このようにして、ヘッダーを設定する最後のフィルターになります。そしてもちろん、すでに述べたように、chain.doFilterを呼び出した後、コードにヘッダーを設定します。

12
Tony Rad

他の人がここで説明しているように応答ラッパーを使用すると仮定すると、秘密は元の応答でgetWriter()をいつ呼び出すかです。これは、ライターを要求した後に追加されたすべてのヘッダーが応答オブジェクトによって無視されるためです。

したがって、getWriter()を呼び出す前に、必ずすべてのヘッダーを追加してください。 doFilter()の推奨シーケンスは次のとおりです。

  1. 応答ラッパーを作成する

  2. chain.doFilter(origRequest、ラッパー);

  3. 必要なすべてのヘッダーを元の(!)応答に割り当てます

  4. 元の応答からライターを取得する

  5. ラッパーのコンテンツをこのライターにコピーします

5
Adi Degani

問題は、フィルターが提供される前に、AjaxRequest(ここではXMLHttpRequest)のヘッダー(X-Wria-Download)がHttpServletRequestオブジェクトに設定されていないことです。

私はより良いアイデアはすることだと思います 専用サーブレットを使用してajaxリクエストを処理します

0

これを試してください:リクエストヘッダーが存在する場合は、リクエストに属性を設定します。次に、chain.doFilter(...)の後に属性を確認し、応答ヘッダーを設定します。

0
Akber Choudhry