Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
こんにちは。d99 です。
最近、Web アプリケーションで対象 IE バージョンの移行を検討されているお客様が多いようで、以下のお問合せが増えてきているため、ご紹介します。
事象
ASP.NET で作成されたファイルダウンロードページで、IE9 まででは問題なくダウンロードできたのに、IE10 以降では「(ファイル名)がダウンロードできませんでした」とエラーになります。
詳細
後述の原因に合致する場合、当該ファイルダウンロードページでは Response.Close() が使用されています。これを Response.End() に置き換えるとエラーが発生しなくなります。
Response.Close() は TCP 接続を強制的に切断するメソッドで、クライアントに対して正しい応答を返すためには一般的には使用されません(クライアントからの悪意のある要求に対して応答せずに接続を切断する、といった場合に使用されます)。Response.End() は ASP との互換のために残されているメソッドではありますが、応答の終了というイメージに近い動作を行います(この際、HttpModule 等、処理パイプライン全体に処理を中断したことを通知するため ThreadAbortException が発報されます)。
HttpResponse.Close メソッド ()
https://msdn.microsoft.com/ja-jp/library/system.web.httpresponse.close(v=vs.110).aspx
HttpResponse.End メソッド ()
https://msdn.microsoft.com/ja-jp/library/system.web.httpresponse.end(v=vs.110).aspx
原因
当該現象は、下記ブログの記事に該当していると考えられます。
IEInternals : Content-Length and Transfer-Encoding Validation in theIE10 Download Manager
https://blogs.msdn.com/b/ieinternals/archive/2012/07/16/content-length-and-transfer-encoding-validation-in-ie10-download-manager-couldnt-be-downloaded-retry-cancel.aspx
IE9 までは、サーバーからのレスポンスにヘッダー Content-Length が含まれない場合や、"Transfer-Encoding:chunked" が指定されている場合であっても転送データのサイズや終端のチェックを厳密に行っていませんでした。
しかし、IE10 以降のダウンロードマネージャーでは、厳密にチェックを行うよう動作が変更されました。この変更により、レスポンスヘッダーにContent-Length が含まれない場合や、チャンク転送でありながら転送データの終端を示す 0-sized chunk が含まれていない場合にはダウンロードを中断し、情報バーに 「(ファイル名) をダウンロードできませんでした。」を表示します。
対処
前述のとおり、Response.Close() は、クライアントとの TCP 接続を強制切断するメソッドになりますので、0-sized chunk は含まれません。しかし、Response.End() であれば、0-sized chunk が含まれますので、有効な対処となります。もし、Response.End() に伴う ThreadAbortException を発生させたくない場合は、HttpApplication.CompleteRequest() をご利用ください。この場合、処理パイプラインを EndRequest まで進めます。
HttpApplication.CompleteRequest メソッド ()
https://msdn.microsoft.com/ja-jp/library/system.web.httpapplication.completerequest(v=vs.110).aspx
ただし、.aspx 等、応答を返すページハンドラにダウンロードを実装されている場合、HttpApplication.CompleteRequest() ではページコンテンツのレンダリングが避けられません。その場合該当ページの Render と RaisePostBackEvent をオーバーライドし、ダウンロード動作の際には基底クラスの同メソッドを呼び出さない事でこれを避ける事が出来ます。
なお、その他の方法としては、ダウンロード専用のカスタムハンドラを作成するといったものが考えられます。
以上です。古い IE の方がいい加減だった、という事例ですね :-)
ではまた。
d99でした。