none
IE10にてWebアプリケーションからExcelファイルをダウンロードできない RRS feed

  • 質問

  • ASP.NET、IISで開発したWebアプリケーションをIE10で動作確認をしたのですが、IE10の環境ではExcelファイルがダウンロードできず以下のようなメッセージが

    出力されます。

    ファイルのダウンロード時にダイヤログより「ファイルを開く」を選択した場合には、ダウンロードできませんでいた。とメッセージが表示され、「再試行」を選択すると

    Excelファイルを開く際には、「開こうとしているファイル は、実際にはその拡張子が示すファイル形式ではありません。」とメッセージが表示されます。

    ダウンロードされたファイルを確認しますと、ファイル名は「.xls」なんですが、ファイルをテキストエディタで開くと中身はHTML形式になっていました。

    また、HUBを使用してPC(クライアント)対PC(ASP.NET、IISで開発したWebアプリケーション)のローカルネットワークの場合には上記のような現象は

    発生せずに正常にファイルのダウンロードはできますが、社内のネットワーク環境下に配置しているASP.NET、IISで開発したWebアプリケーションを操作すると

    上記の現象が発生します。

    WebアプリケーションはIE7、IE8、IE9では問題ありませんが、Windows7+IE10でも同様の現象が発生するので、おそらくIE10での問題ではと考えています。

    Webアプリケーションの処理の概要とコードが以下になります。ご教授宜しくお願いします。

    【処理概要】

    ひな形となるExcelファイルを作成しておき、OLEで編集してクライアントに返す。

    Response.ContentType = "application/vnd.ms-excel"

    Response.AddHeader("Content-Disposition", "attachment; filename=" & System.IO.Path.GetFileName(temporaryPath))

    Response.WriteFile(temporaryPath)

    Response.Flush()

    System.IO.File.Delete(temporaryPath)

    2012年12月25日 8:42

回答

すべての返信

  • > また、HUBを使用してPC(クライアント)対PC(ASP.NET、IISで開発したWebアプリケーション)のローカルネットワークの場合には上記のような現象は発生せずに正常にファイルのダウンロードはできますが、社内のネットワーク環境下に配置しているASP.NET、IISで開発したWebアプリケーションを操作すると上記の現象が発生します。

    こういう場合はまずネットワーク環境に何か依存して発生している可能性を疑いますが??

    経路上の何か所かでネットワーク トレースを採取して、

    • そもそもサーバーが正しくEcxelブックを返しているのか
    • その場合、どこで内容が変わってしまうのか

    を確認されると良いでしょう。

    後はよくあるパターンで ASP.net アプリケーションがUA String でブラウザー判定を行っていて、IE10の判定が正しくできないというパターンですが、テスト環境で正常だとするとこれはなさそうですね。運用環境だと間にプロキシが入って、そこで何かやってるってことはないですか??


    hebikuzure


    2012年12月26日 2:49
    モデレータ
  • IE10でインターネット越しでxlsファイルをダウンロードしてみましたが、再現しませんでした(´・ω・`)
    レスポンスヘッダの一部に次のようなものが付与されています。

    Content-Type: application/vnd.ms-excel
    Content-Disposition: attachment; filename="test1.xls"
    Transfer-Encoding: chunked

     
    以外とダウンロードされた.xlsなHTMLファイルに原因が書かれていたりしませんでしょうか?

    2012年12月26日 13:46
  • 返信ありがとうございます

    レスポンスヘッダーを確認してみました。

    Pragma: no-cache
    Transfer-Encoding: chunked
    Content-Type: application/vnd.ms-excel
    Expires: -1
    Server: Microsoft-IIS/7.5
    Content-Dis; filename=20121227.xls
    X-AspNet-Version: 2.0.50727
    X-Powered-By: ASP.NET
    Date: Thu, 27 Dec 2012 08:05:00 GMT

    また、同じセグメントの社内ネットワーク上では問題なく動作しますが、セグメントが違うネットワークでは正常に動作しないことが判明しました。

    2012年12月27日 8:08
  • Proxyを使用しているか分かりますでしょうか?(異常が発生するネットワークの時)
    手元のインターネット越し(セグメントが違う)では再現しなかったので。
     

    Content-Dis; filename=20121227.xls

    HTTPヘッダとして正しくないようですが、投稿ミスでしょうか?
    また、ご提示のヘッダは、正常時、異常時どちらでしょうか?

    2012年12月28日 3:44
  • 返信ありがとうございます

    Proxyは使用していません。(プロキシの設定の例外にアドレスを記述してプロキシを使用しない。)

    正常時、異常時も同じHTTPヘッダでした。

    HTTP/1.1 200 OK
    Cache-Control: no-cache, no-store
    Pragma: no-cache
    Transfer-Encoding: chunked
    Content-Type: application/vnd.ms-excel
    Expires: -1
    Server: Microsoft-IIS/7.5
    Content-Dis; filename=20121227.xls
    X-AspNet-Version: 2.0.50727
    X-Powered-By: ASP.NET
    Date: Thu, 27 Dec 2012 08:05:00 GMT

    2013年1月8日 10:10
  • HTTPヘッダを貼り付けたのですがうまく反映されないようなので再度記載します。

    Content-Disposition; attachment; filename=20121227.xls

    2013年1月8日 10:14
  • 関係あるかわかりませんが、Expiresヘッダーの値は日時を指定するものですので -1 はおかしいです。
    2013年1月8日 10:54
  • 中身はHTML形式になっていました。

    中身には何が書かれています?


    正常時、異常時も同じHTTPヘッダでした。

    異常時の「再試行」前のときと「再試行」時とでリクエストの内容等に変化があるか分かりますでしょうか?

    それと再現したマシンの台数はどの程度でしょうか?

    # 質問ばかりですが。。

    2013年1月9日 12:56
  • サーバー側のコードで以下のように設定すると、

    Response.Cache.SetCacheability(HttpCacheability.NoCache);
    Response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
    Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));

    応答ヘッダーは以下のようになります。

    Cache-Control: no-cache
    Pragma: no-cache
    Expires: -1

    このケースで Expires が -1 になる理由がどこかに書いてあった記憶があるのですが、探したものの見つけられませんでした。何か理由があるはずなのでもう少し探してみますが、知っている方は教えていただけると幸いです。

    2013年1月9日 13:26
  • 返信ありがとうございます。

    ファイルをダウンロード処理として以下のロジックになっているのですが、「Response.Close()」をコメントアウトするとIE10の環境で動作することを確認できました。

    ファイルダウンロード処理ではお決まりのロジックと認識していまして、詳細には理解できていません。

    ネット上で検索してみますと、「Response.Close()」ではなく「Response.End()」を使用するなどと記載もありますし

    System.Web.HttpResponseクラスのサンプルなどはEnd()もClose()もせず、Flush()だけしています。

    IE10上でのResponse.Close()を使用した場合にダウンロードが出来ない原因、ダウンロード処理ロジックの正しい記述が

    ご存知でありましたらご教授お願いします。

    Response.ContentType = "application/vnd.ms-excel"

    Response.AddHeader("Content-Disposition", "attachment; filename=" & System.IO.Path.GetFileName(temporaryPath))

    Response.WriteFile(temporaryPath)

    Response.Flush()

    System.IO.File.Delete(temporaryPath)

    Response.ClearContent()

    HttpContext.Current.ApplicationInstance.CompleteRequest()

    Response.Close()

    2013年2月5日 8:08
  • はっきりした根拠はありませんが・・・

    Response.Flush() を Response.End() に代えて試してみたらどうなりますか?

    Response.Flush() だと chunked 応答になると思いますが、それでうまく行かなかったという話を聞いた記憶があります。

    Response.End() を使えないのはテンポラリーファイルを消去するためと思いますが、ものは試しということで・・・

    2013年2月5日 13:24
  • ご提示のサンプルでは、chunkedの最後の0が付与されませんでした。
    Close()を明示的に呼び出す際に、End()の呼び出しを避ける方法は見つけられませんでした。(ASPはこれで2度目ですのであしからず)
     
    http://social.msdn.microsoft.com/Forums/ja-JP/aspnetja/thread/067d7e39-c922-4529-b5a1-ebc32a22409b
    上記リンクと同じ事象でしょう
    2013年2月5日 15:23
  • 返信ありがとうございます。

    Response.Flush() を Response.End() に代えてみて実行してみました。

    問題なく動作はしました。(Win8+IE10、Win7+IE9)

    ネットワークキャプチャの応答ヘッダーを確認したところ、Transfer-Encoding: chunkedの項目がなくなりました。

    それは、Response.End()に代えることによって応答する方法が変わったということでしょうか?

    動作はしていますが、上記に記載されていますようにテンポラリーファイルを消去する処理をResponse.End()の前に

    追加することで可能かと考えるのですが、それ以外に代えることによるデメリットはあるのでしょうか?

    2013年2月6日 7:55
  • Response.End()に代えてテンポラリファイルを消去する処理をいれ実行したところ、ファイルダウンロードがなりました。

    Response.End()に代えることによっての影響としては、テンポラリファイルが消去されないというデメリットだけでしょうか?

    また、スキル不足で申し訳ありませんが、IE9.IE10での開発者ツールからのネットワークキャプチャなどからでは、

    chunkedの最後の0と記載があるという部分について表示されていないと思われますし、IE9、IE10でも同じような

    出力結果を得ているので問題ないかと認識しておりました。

    chunkedの最後の0ではない場合の影響度などについてご教授お願いいたします。

    2013年2月6日 8:11
  • Response.Clear って、要らないんだっけ?

    Jitta@わんくま同盟

    2013年2月6日 12:54
  • jitta さん>

    > Response.Clear って、要らないんだっけ?

    HttpResponse.Clear は「すべての内容出力をバッファ ストリームから削除します。」ということですから要らないと思います。

    HttpResponse.Flush で chunked 送信してから HttpResponse.Close(クライアントへのソケット接続を閉じます)したことが問題かと思います。

    2013年2月6日 13:28
  • 全般的に、APIの操作対象のストリームと領域(ヘッダかボディか等)を把握すれば視界が広がりそうですが、
    Response.End()に代えることによって応答する方法が変わったということでしょうか?

    です。
    Response.Flush()でchunkedになる理由は、最終的なサイズ未確定の状態でクライアントに送信するためでしょう。後続処理で追加のデータがあるかもしれないので。
    chunkedのサーバ側の利点は、Content-Lengthが不要なので、最終的なサイズ未確定のまま返信出来ます。
     

    それ以外に代えることによるデメリットはあるのでしょうか?

    多分無いと思いますよ。End()以降に処理を書かなければ。
     

    Response.End()に代えてテンポラリファイルを消去する処理をいれ実行したところ、ファイルダウンロードがなりました。
    DLした中身が正常になるように設定されているか気になります。
     

    chunkedの最後の0ではない場合の影響度などについてご教授お願いいたします。

    0を付与するのは、HTTPのお決まりです。
    逸脱時は未定義という認識です。(ですので、悲観的な見積もりをした方が良いケースが多いです)

    2013年2月6日 14:59
  • jitta さん>

    > Response.Clear って、要らないんだっけ?

    HttpResponse.Clear は「すべての内容出力をバッファ ストリームから削除します。」ということですから要らないと思います。

    HttpResponse.Flush で chunked 送信してから HttpResponse.Close(クライアントへのソケット接続を閉じます)したことが問題かと思います

     すみません、この流れの中に入れるには、言葉が少なすぎました。私が意図しているのは、別の問題です。せめて次の部分の引用を含んでおくべきでした。

    yukimaiさん 2012年12月25日 8:42

    ダウンロードされたファイルを確認しますと、ファイル名は「.xls」なんですが、ファイルをテキストエディタで開くと中身はHTML形式になっていました。

    この部分より、「ダウンロードしたファイルの先頭が HTML 形式である」と認識しています。これは、chunked どうこうには関係ないと思います。同投稿に書かれているコード、2013年2月5日 8:08 の投稿にあるコードとも、HttpResponse オブジェクトに WriteFile メソッドにて、ダウンロードさせたいファイルの内容を流し込んでいます。これらのコードは、同一の部分のようですが、ページの Load イベントか、ダウンロード用のボタン コントロールの Click イベントのハンドラに書かれていると思われます。そうすると、HttpResponse オブジェクトには、すでにいくらかの情報が書き込まれているのではないでしょうか。それを Clear してやる必要はないでしょうか。

     HttpResponse クラスのリファレンスにあるサンプル コードでは、Response.ContentType を設定した直後に Response.Clear を行っています。こちらに提示されているコードではそれがないことが気になりました。


    Jitta@わんくま同盟

    2013年2月7日 11:55
  • 返信ありがとうございます。

    「End()以降に処理を書かなければ。」ということで理解しますと、ファイルをダウンロードするだけの処理であれば、処理の最後のResponse.Close()

    をResponse.End()に代えることによって問題ないということでしょうか。

    Response.ContentType = "application/vnd.ms-excel"

    Response.AddHeader("Content-Disposition", "attachment; filename=" & System.IO.Path.GetFileName(temporaryPath))

    Response.WriteFile(temporaryPath)

    Response.Flush()

    System.IO.File.Delete(temporaryPath)

    Response.ClearContent()

    HttpContext.Current.ApplicationInstance.CompleteRequest()

    Response.End()

    もう1点確認させていただきたいのですが、IE10の開発者ツールでは確認できませんでしたので、「chunkedの最後の0」を確認する方法をご教授お願いします。

    2013年2月7日 12:03
  • >yukimaiさん
    ファイルをダウンロードするだけの処理であれば、処理の最後のResponse.Close()
    をResponse.End()に代えることによって問題ないということでしょうか。
    それで、返却されたデータそのものは問題ありませんでした。
    Response.End()は互換性のために残されているとのことで、どうにか避けたいのですが、他にうまく返却する方法は発見出来ませんでした。
     
    「chunkedの最後の0」を確認する方法をご教授お願いします。
    wiresharkやnetwork monitorといったキャプチャツールが良いと思います。サーバとクライアントが同じマシン同士でなければ。
    マイナーでちょっと癖がありますが、クロスブラウザ等や同じマシン同士でも使えるよう、私はレイヤ4レベルリピータを使う場合があります。今回はこれを使用しました。
    http://www.gcd.org/sengoku/stone/Welcome.ja.html

     
    >jittaさん
    IIS8でWebフォームのapsxをご提示のリンク先のものに丸ごと差し替えてみましたが、画面上は正しく見えましたが、
    パケットを見てみると、画像の後ろにHTMLもくっ付いていました。
    私にはASP.NETの難易度半端ない感じです/(^o^)\
    2013年2月7日 14:23
  • jitta さん

    返信ありがとうございます

    ファイル名は「.xls」でファイルの中身がHTMLになる場合としては、ファイルをダウンロードする際に、ダウンロードダイヤログより「開く」、「保存」を押下し

    ダウンロードできませんでしたと表示後に「再試行」のボタンを押下した際に同じイベントが実行されるのではなく別の命令が呼び出されているようです。

    ダウンロード時の呼び出し

    POST 200 application/vnd.ms-excel

    再試行時の呼び出し

    GET 200 text/html

    原因はわかりませんが、IEからの呼び出しに変わってしまってますね。ダウンロードマネージャーの不具合かもですね。

    2013年2月8日 0:57
  • 返信ありがとうございます

    キャプチャーツールを使用してIE10以外でのchunkedを確認したいと思います。

    ファイルダウンロード時の処理として、Response.Close()、Response.End()の扱いなど有償サポートを

    受けた方がいいのでしょうか。

    2013年2月8日 1:05
  • jitta さん>

    > ページの Load イベントか、ダウンロード用のボタン コントロール
    > の Click イベントのハンドラに書かれていると思われます。そうす
    > ると、HttpResponse オブジェクトには、すでにいくらかの情報が書
    > き込まれているのではないでしょうか。それを Clear してやる必要
    > はないでしょうか。

    レンダリング順序が明記されている Microsoft の公式文書は見つけられませんが、自分が今まで試した限りでは、Load や Click のイベントにおいて HttpResponse.WriteFile などを使ってストリームに書き込むほうが、Page の html 要素が書き込まれるより早いようです。

    jitta さんの紹介されていたページのサンプルコードで言うと、まず bmp.Save(Response.OutputStream, ImageFormat.Jpeg); で最初に画像データがストリームに書き込まれ、その後 Response.Flush(); で画像データがクライアントに chunked 送信され、最後に <!DOCTYPE で始まる html コードが送信されるはずです。

    (´・ω・`)さんが実際に試した結果(「パケットを見てみると、画像の後ろにHTMLもくっ付いていました」)がそれを裏付けていると思います。

    Response.Clear(); は不要なはずですが、念のため置いてあるように思います。

    Response.Flush(); の代わりに Response.End(); を使えば「画像の後ろにHTMLもくっ付いて」はなくなるはずです。chunked 送信もしなくなるはずです。


    (´・ω・`)さん>

    > Response.End()は互換性のために残されているとのことで、
    > どうにか避けたいのですが、他にうまく返却する方法は発見
    > 出来ませんでした。

    気がつかなかったのですが .NET 4 からそういう説明が追加されていますね。代わりに HttpApplication.CompleteRequest() を呼び出せと書いてあります。.NET 3.5 以前にはそのような説明はなかったのですが。

    で、使ってみると、やっぱり「画像の後ろにHTMLもくっ付いて」きます。それでも問題なく画像は表示されますが、気持ち悪いので Response.End(); を使ったほうがよさそうです。

    ただし、そうすると質問者さんのケースではテンポラリーファイルが削除できないという問題は残りますが。

    残る手段は http ハンドラを使うことでしょうか。


    • 編集済み SurferOnWww 2013年2月8日 13:40 誤記訂正
    2013年2月8日 13:38
  • >SurferOnWwwさん

    HTMLがくっ付いてくる時点で、画像フォーマットなり、Excelフォーマット仕様を満たせなくなると思います。
    chunked 0と同様で、逸脱時は悲観的な見積(略)だと思います。
     

    残る手段は http ハンドラを使うことでしょうか。

    おお、こんなものが。「ジェネリックハンドラー(ashx)」、良さそうですね。
    調べてみるとまさに画像やバイナリファイル返却するために使用するものだと思いました。
    使ってみても正常に動作しました。
    Flush()、End()、Close()、XxClear()等についても必要がなければ呼ぶ必要もなくなりますね。
     
     
    >yukimaiさん

    ダウンロードマネージャーでリトライ時にメソッドが変わる事象は、
    Rangeリクエスト(部分的GET)になっているのでは?
    chunked 0が付与されていないため、途中で切れたと判断され、ダウンロードの続きを再試行しているのだと思いました。
    # POSTですと一般にサーバ側のデータ書き換えの可能性も高くなりそうですし。
     

    ファイルダウンロード時の処理として、Response.Close()、Response.End()の扱いなど有償サポートを受けた方がいいのでしょうか。
    現在、私はaspxにこだわっていると、HTMLがくっつく問題は解消しないと思っています。(End()呼び出しを除けば)
    aspxに直書きしたHTMLをクリア出来るケースは存在しないように思えますし、
    aspxファイル上からHTML消しても改行が付与されるケースが懸念されます。
    そもそもaspxで、バイナリファイルの返却は出来ないと考えた方が良いのではと思いました。 
    # Pageのクラスを派生させてバイナリファイル(ページとは言えない)を返却することに疑問を感じていました。 
     
    要するに、asp.netでサイトを構築する際は次のようにするものだと思いました。
    Webページ系: aspx
    バイナリ・XML系応答: ashx
     
    次のような「HTTPハンドラ」のイメージをしました。
    public void ProcessRequest (HttpContext context) {
        HttpResponse Response = context.Response;
        Response.ContentType = "application/vnd.ms-excel";
        Response.AddHeader("Content-Disposition", "attachment; filename="& System.IO.Path.GetFileName(temporaryPath));
        Response.WriteFile(temporaryPath);
        System.IO.File.Delete(temporaryPath);
    2013年2月9日 5:51
  • 返信ありがとうございます。

    そもそもの問題としては、Response.Closeを使用しているとIE10ではファイルのダウンロードはできませんが、

    IE7~IE9までは動作していますのでIE10の機能強化などが影響しているのでしょうか?

    chunkedについてはまだ確認はしていないのですが、IE7~IE9の環境ではなんとなく動作していて、

    IE10では、chunkedの影響で動作しなくなったんでしょうか?

    IE7~IE10環境でファイルダウンロードするにはロジックの改修が必要ということになるんでしょうか?

    2013年2月18日 10:07
  • 回答者のレスをきちんと呼んでいるのでしょうか? 質問の回答はすべて書いてありますよ。もし書いてあることが理解できてないのであれば、そこを自助努力で何とかしてもらわないと、掲示板で解決するのは無理だと思います。
    2013年2月18日 12:58
  • そもそもの問題としては、Response.Closeを使用しているとIE10ではファイルのダウンロードはできませんが、

    IE7~IE9までは動作していますのでIE10の機能強化などが影響しているのでしょうか?

    原因は私にも分かりません。(再現環境を構築する手間をとれません。)
    ご提示の情報ではルータ?等が影響しているかも分かりませんでした。
    MSのサポートに問い合わせてみると何か得られるかもしれません。

    IE7~IE10環境でファイルダウンロードするにはロジックの改修が必要ということになるんでしょうか?

    ロジックもハンドラも変更の必要がありそうです。

    2013年2月20日 13:16
  • 返信ありがとうございます。

    Google Chrome で HTTP リクエスト・レスポンスヘッダを確認しました。

    WinXP IE8環境にて動作確認したところファイルは問題なくダウンロードできましたが、

    HTTP リクエスト・レスポンスヘッダを確認したところエラーが記述されていました。

    正常に動作しているように見えていても不安定な状態で動作していたんですね。

    以下のサイトにファイルのダウンロード機能を実装する方法がありましたのでコードを修正し、

    動作確認してみるととエラー記述はなかったと思われます。

    IE7~IE10の環境で検証後、問題がなければコードの改修を実施したいと思います。

    http://msdn.microsoft.com/ja-jp/library/cc719227.aspx

    2013年2月21日 10:29
  • (´・ω・`)さん 

    wiresharkでchunkedの確認をしました。

    任意のTCPデータを右クリックし、”Follow TCP Stream”をクリックし、サーバからのデータの最後に「0」が表示されていれば正常にファイルがダウンロードされたという認識でいいということでしょうか。

    英語で記載されている文献をしらべたところ、IE10のダウンロードマネージャでのContent-Length/ Transfer-Encodingのチェックを再び有効に設定されているということがわかりました。

    処理の最後にResponse.End()にすることで問題は解消できるのではと考えております。

    2013年3月4日 9:49
  • 任意のTCPデータを右クリックし、”Follow TCP Stream”をクリックし、サーバからのデータの最後に「0」が表示されていれば正常にファイルがダウンロードされたという認識でいいということでしょうか。

    その認識でよいです。最後の行頭に0が来て改行が2個あるかと思います(通常は)。
     

    英語で記載されている文献をしらべたところ、

    おおっ、こちらですね。まさに今回の事象ですね。
    Content-Length and Transfer-Encoding Validation in the IE10 Download Manager - IEInternals - Site Home - MSDN Blogs

     

    処理の最後にResponse.End()にすることで問題は解消できるのではと考えております。

    End()にすることでダウンロード出来ないという問題は解消します。
    HTTP的に正しく、どのブラウザでもダウンロードも正常に行われるようになると思います。
     
    End()の欠点は、以下に書かれており、
    http://msdn.microsoft.com/ja-jp/library/system.web.httpresponse.end.aspx
    http://blogs.msdn.com/b/aspnetue/archive/2010/05/25/response-end-response-close-and-how-customer-feedback-helps-us-improve-msdn-documentation.aspx
    ASP1.0との互換のためであることと、処理が重いらしいです。(秒間のDL数が多いなら特に検討するとよいかもです)。
    私の前々回のレス等は、このEnd()の欠点を回避する案を模索していました。

    2013年3月4日 16:00
  • フォーラム オペレーターの星 睦美です。
    yukimai さん、こんにちは

    今回のyukimai さんからの質問には複数のコミュニティの回答者から参考になる情報がたくさんありますが、
    (´・ω・`)さんの返信が[回答の候補としてマーク] されています。

    役立つ内容の回答がありましたら、今後もコミュニティでの質問と回答が活発に行われますように、ぜひ投稿者から[回答としてマーク] いただければと思います。
    (お忘れになっているような場合には後ほど私から[回答としてマーク]させていただきますね。)

    それではこれからもIntetnet Explorer フォーラムをお役立てください。


    日本マイクロソフト株式会社 フォーラム オペレーター 星 睦美

    2013年4月11日 5:42