- - PR -
Struts Action クラスで PDFダウンロード キャンセル時にエラー
1
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2006-11-10 11:40
はじめまして。JAVA初心者です。
サーバー上のPDFファイルをダウンロードするStruts Actionクラスを作成していますが エラーが発生し、困っております。 長文で申し訳ありませんが、原因や対策をご存知の方がいらしたら、教えてください。 よろしくお願いします。 【環境】 ------------------------------------------------------------------------------ サーバー Tomcat5.5.17 Struts1.2.9 WindowsXP Professional 2002 SP2 ブラウザ IE6 ------------------------------------------------------------------------------ 【現象】 ------------------------------------------------------------------------------ [ファイルのダウンロード] ダイアログ ボックスが表示され 「開く(O)」「保存(S)」をクリックした場合は、正常動作。 [ファイルのダウンロード] ダイアログ ボックスが表示され 「キャンセル」「×」をクリックした場合は、エラー。 ただし、ファイルのサイズが小さい場合(35KBまで確認)は、正常動作。 ------------------------------------------------------------------------------ 【エラー内容】(ブラウザには表示されず、Tomcatコンソールで確認) ------------------------------------------------------------------------------ 致命的: サーブレット action のServlet.service()が例外を投げました java.lang.IllegalStateException: getOutputStream()はこのレスポンスに対して既に呼び出されています ------------------------------------------------------------------------------ 【ソース】 ------------------------------------------------------------------------------ final String TMP_OUTPUT_FILE = "/WEB-INF/aa.pdf"; String tmpOutputPath = this.getServlet().getServletContext().getRealPath(TMP_OUTPUT_FILE); File outputFile = new File(tmpOutputPath); response.setHeader("Cache-Control", ""); response.setHeader("Pragma", ""); response.setHeader("Content-Disposition","attachment;filename=aa.PDF"); response.setContentType("application/pdf" ); FileInputStream in = new FileInputStream(outputFile); OutputStream os = response.getOutputStream(); byte[] buffer = new byte[8192]; int bytes; while ((bytes = in.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytes); } in.close(); os.close(); return null; ------------------------------------------------------------------------------ 実行状況をコンソールで確認したところ、以下のことがわかりました。 ●ファイルサイズが小さい場合 ダイアログボックス表示と同時に、Actionクラスが最後まで実行されて正常終了。 ●ファイルサイズが大きい場合 ダイアログボックス表示後、 「開く(O)」「保存(S)」「キャンセル」「×」のいずれかのボタンを クリックするまで、Actionクラスが待ち状態。 「開く(O)」「保存(S)」をクリックすると、Actionクラスが最後まで実行されて正常終了。 「キャンセル」「×」をクリックすると、Actionクラス再開直後にエラー。 バッファのサイズは、最初2048だったものを8192に変更してみたのですが 現象は変わりませんでした。 また、通常のサーブレットとして同じソースを実行したところ 上記の現象は発生しませんでした。 正常動作となるファイルサイズの上限値は、調査中です。 よろしくお願いします。 | ||||||||||||
|
投稿日時: 2006-11-10 13:43
ブラウザ側でキャンセルすると、送信途中のTCPセッションが切断され、 ServletOutputStreamへの書き込み時にIOException発生します。 メッセージはConnection reset by peerになるはずです。 続いてアプリケーションのエラー処理でエラーページにforwardすることに なりますが、レスポンスの送信は始めているのでエラーとなります。 「このレスポンスに対して既に呼び出されています」は後者のエラーです。 普通のHTML程度のサイズならばRSTを受け取るまでに送信が終わるので キャンセルされてもConnection reset by peerは発生しないのですが、 ファイルのダウンロード系では頻繁に起こってしまう現象です。 数KBのレスポンスでも発生する可能性はありえますし、 放っておいても実害はないと思いますよ。 どうしてもエラーページへのforwardをやめさせたいのであれば、 ServletResponse#isCommitted()で判断できるかもしれません。 | ||||||||||||
|
投稿日時: 2006-11-10 14:45
早速の回答、ありがとうございます。
発生し得る現象であり、実害もないとのことで安心しました。
catchの中で、ServletResponse#isCommitted()を取得することができました。 下記のように対応しようと思います。
今後のためにお聞きしたいのですが サーブレットとStrutsActionで動作が異なるのは、仕様がが異なるからなのでしょうか。 それとも今回は、たまたまStrutsでは発生していないだけなのでしょうか。 よろしくお願いします。 | ||||||||||||
|
投稿日時: 2006-11-10 14:57
なんか誤解されているように思います。 やや語弊がありますがStrutsもServletですよ。 | ||||||||||||
|
投稿日時: 2006-11-10 15:46
申し訳ありません。説明不足でした。
Strutsを使用しないサーブレット(下記1)のdoPost(またはdoGet)で実行したときと、 Strutsを使用したとき(下記2)では、動作が異なるのです。 (1)
(2)
同じプログラムでも、今回の現象が発生するのは(2)だけです。 かなり大きなサイズのPDFファイルでも、(1)では発生しないのです。 |
1