web-dev-qa-db-ja.com

ブラウザにファイルをダウンロードさせるにはどうすればよいですか?

すべてが正常に機能しますが、ファイルが1MB程度の小さい場合にのみ、ブラウザが表示する20MBなどの大きなファイルで試してみたところ、ダウンロードを強制する代わりに、今まで多くのヘッダーを試しました。

PrintWriter out = response.getWriter();
String fileName = request.getParameter("filename");

File f= new File(fileName);

InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);

while(din.available() > 0){
    out.print(din.readLine());
    out.print("\n");
}

response.setContentType("application/force-download");
response.setContentLength((int)f.length());
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName);


in.close();
bin.close();
din.close();
53
dieeying

ファイルの内容を出力ストリームに書き込んだ後、応答ヘッダーを設定しています。これは、ヘッダーを設定する応答ライフサイクルのかなり遅い段階です。操作の正しいシーケンスは、最初にヘッダーを設定してから、ファイルの内容をサーブレットの出力ストリームに書き込むことです。

したがって、メソッドは次のように記述する必要があります(これは単なる表現であるためコンパイルされません)。

response.setContentType("application/force-download");
response.setContentLength((int)f.length());
        //response.setContentLength(-1);
response.setHeader("Content-Transfer-Encoding", "binary");
response.setHeader("Content-Disposition","attachment; filename=\"" + "xxx\"");//fileName);
...
...
File f= new File(fileName);

InputStream in = new FileInputStream(f);
BufferedInputStream bin = new BufferedInputStream(in);
DataInputStream din = new DataInputStream(bin);

while(din.available() > 0){
    out.print(din.readLine());
    out.print("\n");
}

失敗の理由は、サーブレットによって送信される実際のヘッダーが、送信しようとしているものと異なる可能性があるためです。結局のところ、サーブレットコンテナーがどのヘッダー(HTTP応答の本文の前に表示されるか)を知らない場合、適切なヘッダーを設定して、応答が有効であることを確認できます。したがって、ファイルが書き込まれた後にヘッダーを設定することは無駄であり、コンテナーが既にヘッダーを設定している可能性があるため、冗長です。 WiresharkまたはFiddlerやWebScarabなどのHTTPデバッグプロキシを使用してネットワークトラフィックを調べると、これを確認できます。

この動作を理解するには、Java ServletResponse.setContentType のEE APIドキュメントを参照することもできます。

応答がまだコミットされていない場合、クライアントに送信される応答のコンテンツタイプを設定します指定されたコンテンツタイプには、文字エンコーディング仕様が含まれる、たとえば、text/html; charset = UTF-8。 getWriterが呼び出される前にこのメソッドが呼び出された場合、応答の文字エンコーディングは指定されたコンテンツタイプからのみ設定されます。

このメソッドは、コンテンツタイプと文字エンコーディングを変更するために繰り返し呼び出される場合があります。 このメソッドは、応答がコミットされた後に呼び出されても効果がありません。

...

65
Vineet Reynolds

Content-typeおよびその他のヘッダーを設定しますbeforeファイルを書き出します。小さなファイルの場合、コンテンツはバッファリングされ、ブラウザは最初にヘッダーを取得します。大きなものの場合、データが最初に来ます。

5

これは、テストしたすべてのブラウザーで問題を完全に解決するphpスクリプトからのものです(3.5以降のFF、IE8 +、Chrome)

header("Content-Disposition: attachment; filename=\"".$fname_local."\"");
header("Content-Type: application/force-download");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($fname));

だから、私が見る限り、あなたはすべてを正しくやっている。ブラウザの設定を確認しましたか?

4
f1sh