none
CSVダウンロードの保存ダイアログでhtml形式となる RRS feed

  • 質問

  • Webアプリケーションからのファイルダウンロードについてご質問です。

    ・クライアント環境(WindowsXP/IE6,7,8)

    プログラム側ではContentTypeを"application/octet-stream"と設定しており、ヘッダ(Content-Disposition: )には、filename=xxx.csvとセットしていますが、ファイル保存ダイアログでは拡張子がHTML形式で表示されてしまいます。

    クライアント環境にofficeはインストールされています。

    サーバー(WindowsServer2008)にはofficeはインストールされていませんが、MIMEの種類の設定はしています。(.csv : application/octet-stream)

    拡張子が変わってしまう原因は何でしょうか?

     

    2011年5月12日 7:24

回答

  • > ヘッダ(Content-Disposition: )には、filename=xxx.csvとセットしていますが、

    attachment; filename=xxx.csv としていますか?

     

    2011年5月12日 12:50
  • Content-Disposition: attachment; filenaame=xxx.csv

    のうち「filename」部分の綴りが違うとダウンロードダイアログは開くものの、ファイル名が定まらずURLを元にしたファイル名(xxx.aspxなど)になりそうですが。

    2011年5月13日 1:18
  • 私も同様の件で、調べておりました。

    Response.ContentType = "application/x-csv"

    とすると、正常に動作しました。

    参考にしたのは、下記のURLです。

    http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=12433&forum=12

    ご参考までに。

    2011年5月13日 4:48
  • > Response.AddHeader("Content-Disposition", "attachment; filename=xxx.csv")
    >
    > としています。
    >
    > この現象はお客様環境で起こっていますが、弊社内のテストでは起こりません。

    そうであれば、「お客様環境」に問題がある以外に原因はないと思いますが。

    パケットキャプチャツールで、実際に受信している HTTP ヘッダがどうなっている
    か調べてみてはいかがですか?

     

    2011年5月13日 13:12
  • 再現しました(`・ω・´)。

    確認したのは次の3環境で1環境のみ再現しました。IE6のみです。
    ①XP SP2 & IE6 & Officeなし
    →再現する
    ②XP SP3 & IE7 & Officeなし
    →再現しない
    ③7  SP1 & IE9 & Officeあり
    →再現しない
     
     
     
    【【事象確認】】
    再現したとは、次の事象を指しています(長いです)。
     
    ・HTMLには次の記載
     
    <a href="test1.cgi">test1.cgi</a>
     
    ・test1.cgiへリクエストされるとヘッダ部は
     
    Content-type: application/octet-stream
    Content-Disposition: attachment; filename="aaa.csv"
     
    ボディ部は「a,b,c」という5バイトの応答をします。
     
     
    HTMLを表示し、現れるリンクtest1.cgiをダウンロードするために左クリックすると以下が表示されました。(とりあえず、”ダウンロード確認ダイアログ”と呼ぶことにします)
     

    注目したいのは、
    ・”アイコン画像”がHTMLのものになっている
    ・"種類"欄が「HTML Document」になっている。
    ・"名前"欄には「aaa.csv」と正しく表示されている。
    ことかと思います。 

    ”アイコン画像”、”種類”、”名前”欄のいずれも、後述の画面とは違い、ファイルの中身を変えても変わりませんでした(確認時はキャッシュは消しています)。 またリクエストする.cgiを.aspcという通常は存在しない拡張子にし、サーバの設定を.aspcをCGIとして動作させたとしても変わりませんでした。
    ※IE9ではこの画面は出ず、一新されています。 
     
     
    その後、「保存」ボタンを押すと次の画面が表示されました(一般に"ファイル保存ダイアログ"と呼んでいるもの)。
    注目したいのは、
    ・"ファイルの種類"欄が「テキスト文章」となっている。
    ・”ファイル名”欄が拡張子が出ていない
    かと思います。 
     
    ”ファイルの種類”については、csvのファイルの中身がHTMLっぽいものにしておくと「HTML Document」になりました。
    ”ファイル名”については 「フォルダオプション」で「登録されている拡張子を表示しない」となっているためでした、表示するようにすると表示されました。
    拡張子を表示しようとしまいと、そのまま保存したときの実際のファイル名は「テキスト文章」でも「HTML Document」でも「aaa.csv」になりました。
    ※なお、「フォルダオプション」の「ファイルの種類」欄には拡張子CSVの登録はありません。 
     
     
    【【ネット上を検索】】
    似たようなの事象として、以下がありました。
    IE8でも起きることがあるようです。
     
    商品情報CSVのダウンロードをすると、CSVの拡張子でHTMLがダウンロードされる
    http://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=7514&forum=11
     
    CSVが保存ダイアログでHTMLになる
    http://okwave.jp/qa/q6443040.html
     
     
     
    【【本当の問題点の確認】】
    書いてきたように、当方の環境では、実際に保存されるファイル名は正しく保存されていました。
    また、"ファイル保存ダイアログ”の”ファイル名”の拡張子は.csvでした。
     
    >ファイル保存ダイアログでは拡張子がHTML形式で表示されてしまいます。
    お客様環境で起こっているのは、
    「”ダウンロード確認ダイアログ”で、 "アイコン画像”と”種類”がHTMLのものが出ている」ではないでしょうか?
    ファイル保存ダイアログで拡張子がHTML形式で表示されるのではなく)
    以上について、ご確認ください。
     
    もし、ファイル名も正しくない場合は以下が参考になると思います。
    ファイルのダウンロードダイアログで表示されるファイル名の命名規則 
     
     
     
    【【・・・で】】
    >他に原因は考えられませんか?
     
    ようやく、ここから本題です。何か考えられる予想が欲しいとのことですね。
    問題が起きているのは「保存時のファイル名」ではなく「アイコン画像」と「種類」という前提で話を進めると、
     
    最初は単に、次のようなことが影響していると思っていました。
    http://www.atmarkit.co.jp/fcoding/articles/webapp/02/webapp02a.html
    ①「拡張子ではなく、内容によってファイルを開くこと」の設定
    ②URLの拡張子
    ③IE以外のアプリケーションの設定
     
    例えば、Proxy(*.pac)接続かどうかでゾーンが変わったため設定が変わり、sniffing動作が変わった結果起きたのではないかなどと予想していました。
     
    が、当方では、いずれも該当しないようでした。
    ①の設定の有り無しを変えてみましたが、アイコンの種類は変わりませんでした。
    ②の設定の変更(.cgiを.aspxにしたり)してみましたが、アイコンの種類はHTMLのものでした。
    ③については、そもそも再現確認用のクリーンな環境です。
    「フォルダオプション」の「ファイルの種類」にはcvsは登録されていません。「アプリケーションの追加と削除」 には、「Flash Player」「Fiddler2」「VMware tools」「Windows Installer」の4つのみです。
    HKCR\MIME\Database\Content Typeにはoctet-streamの登録はありません。
     
    ですので、IE6は素の動きで、octet-stream時にcsvをHTMLとして保存する動作(しかし拡張子は.csv)になっているようです。
    書いてきたように、当方で再現した環境とお客様環境ともにofficeが入っていませんが、同じofficeが入っていない環境でも再現しない環境がありました。
    2011年5月16日 15:34
  • Excel がインストールされている環境の HKCR に登録される .csv の MIME Type は application/vnd.ms-excel ですね。

    サーバーからこのMIME Type を返すとどうなるのでしょうか。

    また MIME Sniffing が影響している可能性が考えられますから、以下の KB の WORKAROUND にある設定を試すと動作に変化が出るかもしれません。

    http://support.microsoft.com/kb/925832/en-us

     


    hebikuzure
    2011年5月21日 3:13
    モデレータ
  • IE6 (IE Tester の), IE8, IE9 で試してみましたが、拡張子が
    htm になるのが再現できたのは、ヘッダが以下のときのみでした。

    Content-Type: text/html
    Content-Disposition: attachment; filename=

    (注)上記で、Content-Type: text/html となっていますが、プロ
    グラムで HttpResponse.ContentType を指定しない場合 IIS
    が Content-Type: text/html を追加します。

    Content-Disposition ヘッダで、拡張子は正しく指定しているとの
    ことですが、途中にプロキシなどがあって、ヘッダを書き換えてい
    るというようなことはないでしょうか?

    くどいようですが、パケットキャプチャツールで、実際に問題の PC
    が受信している HTTP ヘッダがどうなっているか調べてみてはいかが
    ですか。


    以下補足

    当方で試した限りでは、参考にされていたマイクロソフトのサポート
    ページ(下記)に書いてあった通りの結果になりました。

    ファイルのダウンロードダイアログで表示されるファイル名の命名規則
    http://support.microsoft.com/kb/436153/ja

    即ち、「Content-Disposition: ヘッダが存在する場合は、filename パ
    ラメータで設定されたファイル名が利用されます。」ということです。

    サポートページには書いてないですが、Content-Disposition: ヘッダ
    でファイル名が指定してあれば、Content-Type: の指定は無視されます。

    2 番目の「HTTP レスポンス内に存在する、送られてきた Content-Type
    が、レジストリの HKEY_CLASS_ROOT\MIME\Database\Content Type 以下
    に存在するかどうか・・・」というのは、Content-Disposition: ヘッダ
    の filename パラメータにファイル名の指定がない場合に限るようです。

    具体的な例としては、ヘッダが以下のような場合で、この場合は拡張子
    が xls に書き換えられます。

    Content-Type: application/vnd.ms-excel
    Content-Disposition: attachment; filename=

    ご参考までに検証に使ったコードをアップしておきます。aspx ページは
    以下の URL でアクセスできますので、興味があれば試してみてください

    http://surferonwww.info/Test/csvdownloadtest.aspx


    aspx ページ (CsvDownloadTest.aspx)

    <%@ Page Language="C#" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script

    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:HyperLink ID="HyperLink1"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=1">
                filename="", ContentType=""
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink2"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=2">
                filename="", ContentType="application/octet-stream"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink3"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=3">
                filename="test.csv", ContentType="application/octet-stream"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink4"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=4">
                filename="test.csv", ContentType="text/csv"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink5"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=5">
                filename="test.csv", ContentType="application/vnd.ms-excel"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink6"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=6">
                filename="test.csv", ContentType=""
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink7"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=7">
                filename="", ContentType="application/vnd.ms-excel"
            </asp:HyperLink>
        </div>
        </form>
    </body>
    </html>

     

    HTTP ハンドラ (CsvDownloadHandler.ashx)

    <%@ WebHandler Language="C#" Class="CsvDownloadHandler" %>

    using System;
    using System.Web;
    using System.Text;

    public class CsvDownloadHandler : IHttpHandler {
       
        public void ProcessRequest (HttpContext context)
        {
            string type = context.Request.QueryString["type"];
            switch (type)
            {
                case "1":
                    SetHeader(context, String.Empty, String.Empty);
                    break;
                case "2":
                    SetHeader(context, String.Empty, "application/octet-stream");
                    break;
                case "3":
                    SetHeader(context, "test.csv", "application/octet-stream");
                    break;
                case "4":
                    SetHeader(context, "test.csv", "text/csv");
                    break;
                case "5":
                    SetHeader(context, "test.csv", "application/vnd.ms-excel");
                    break;
                case "6":
                    SetHeader(context, "test.csv", String.Empty);
                    break;
                case "7":
                    SetHeader(context, String.Empty, "application/vnd.ms-excel");
                    break;
                default:
                    return;               
            }
           
            Encoding enc = Encoding.GetEncoding("shift_jis");
            string csvString = GetCsvString();
            context.Response.BinaryWrite(enc.GetBytes(csvString));
            context.Response.End();
        }
       
        protected void SetHeader(HttpContext context, string name, string type)
        {
            context.Response.AppendHeader("Content-Disposition",
                "attachment; filename=" + name);

            if (!String.IsNullOrEmpty(type))
            {
                context.Response.ContentType = type;
            }

            context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
            context.Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));
            context.Response.AppendHeader("Pragma", "no-cache");
        }

        protected string GetCsvString()
        {
            string text = "a,b,c\nあ,い,う\n";
            return text;
        }
       
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

    }

     

    2011年5月21日 8:00
  • MIME Sniffing、実は影響していないと思うようになりました。(理由は後述)

    ネットワーク、Office、IEの切り分けは出来ていませんが、
    ダイアログを出す時点で拡張子(シェル拡張?)ハンドラ側でファイル名を正規化出来る仕組みってあるんですっけ?

    あとはおっしゃるようにProxy、Office、HTTP圧縮、SSL(cache周り)でしょうか。

    Mimeハンドラ動作時は、拡張子は入れ替わる(後ろに加わるではなく)という認識ですが、
    Officeは拡張子を後ろにくっつける印象を受けているため、Officeかなという気がしています。
    officeかどうかはどうでもよいとして、「くっつく」のか、「入れ替わる」かの違いは、結構重要だと思っています。
    sniffingするしないに関わらず、どちらかじゃないとおかしいですよね。「入れ替わる」方が正解なのでは。
    (ネットワークかどうかの確認は取りたいのは山々ですが、)。


    >SurferOnWwwさんからの引用
    >拡張子が xls に書き換えられます。
    「書き換えられる」のですね(Dispositionヘッダなし時)。「追加」されるではなく。


    以下、「>」は引用、「→」が思ったことです。(特に③、⑨が注目です)


    ■Content-Dispositionありでもファイル名は変更されるよ派
    ①IE6 でダウンロードする際、正しいファイル名が得られない現象
    http://d.hatena.ne.jp/e-kuroda/20070818/1187446917
    →とりあえず関係するのは前半部分だと思います。

    ②Internet Explorer 6 でダウンロード ダイアログに正しいファイル名が表示されない
    http://support.microsoft.com/kb/939251/ja
    >HTTP 圧縮を使用する環境では、Content-Disposition ヘッダーで指定されたファイル名は使われず、URL で指定した "test.asp" がファイル名として表示されます。
    →aspのようなので、拡張子が.csv.htmlになっている以上、ファイル名は使われているはず。Content-Encodingヘッダは避けた方がよさそうです。IE8,9でも同様の現象かは気になります。

    ③[IE] ファイルのダウンロードで、IEが.xmlという拡張子を自動で付与しちゃう
    http://cast-a-spell.at.webry.info/200803/article_10.html
    →拡張子が追加で付与されるケースと、入れ替わるケースの2つが書かれている気がしています。
    上記にも書きましたが、以下の認識です。
    ●拡張子が追加で付与
    未知の”何か” → 条件としてファイルの中身の記載もありましたので、sniffingも関係していました。(条件がこのサイトどおりであれば、ネットワークの可能性もほぼ消えそうです)
    ●拡張子入れ替わり:mime sniffing
      これは、単に、Content-Dispositionヘッダが付与されないパターンのケースなので、妥当&今回の件には関係なしと考えています。SurferOnWwwさんの試験結果と同じ。

    →たまたまでしょうけど、驚くのが、後述の⑨番のリンクの記載の中で、ちょうど"text/plain"と"octet-stream"というmime-sniffing処理の判定の中で特別視するものでは再現している模様。

    ④余分なファイルの拡張子がダウンロードされたファイルに追加します。
    http://support.microsoft.com/kb/231755/ja
    > Windows に登録されていないファイルの種類に発生することができます
    →Internet Explorer 5.0の話でIE6でも有効かは不明。Content-Dispositionなしの場合の話かなこれは。

    ⑤Office 2007
    修正: ファイルを保存するとファイル名拡張子が追加される
    http://office.microsoft.com/ja-jp/powerpoint-help/HP001165938.aspx
    →この辺が動作する条件であれば、現象は納得なのですが。

     

    ■Content-Dispositionあり時はファイル名は変更されないよ派
    ⑥Handling MIME Types in Internet Explorer
    http://msdn.microsoft.com/en-us/library/ms775148(v=VS.85).aspx
    >If the file is marked as "content-disposition=attachment" in the HTTP header, Internet Explorer treats the file name from the URL as final and does not rename it before placing it in the cache.
    →キャッシュにおく前は、ファイル名の変更はしない模様。
    じゃぁダイアログにはその名前がそのまま出るの?

    ⑦イベント 1021 - MIME 処理制限
    http://technet.microsoft.com/ja-jp/library/cc749557(WS.10).aspx
    >These changes do not affect cases where the file uses a Content-Disposition: attachment HTTP header.
    →Content-Disposition: attachmentを指定していれば、拡張子変更のロジックは動作しない。
    Applies To: Windows 7, Windows Vistaなページですが、2003SP1のサイトでも同じ内容なのでXP SP3も同じはず。
    →Mimeハンドラをスキップすることは分かりましたが、拡張子ハンドラは動作するとのこと。

    ⑧IE content-type logic - IEBlog
    http://blogs.msdn.com/b/ie/archive/2005/02/01/364581.aspx
    >Mimesniffing doesn't mean that there is no way for a server to control how a file is handled. <Content-disposition: attachment; filename="filename.ext"> header enables a server to do precisely that. With this however, IE makes sure that the user gets prompted with the file type information (based on the extension specified by the server here) before the file is opened/saved.
    →おそらく、もろもろの元ネタ。

    ⑨MIME Type Detection in Internet Explorer
    http://msdn.microsoft.com/en-us/library/ms775147(v=VS.85).aspx
    →Mimeハンドラ(FindMimeFromData)の動作があります。
    この辺の"text/plain"と"application/octet-stream"時の分岐の一部のルートに落ちたケースじゃないでしょうかね。
    英語得意な方であれば、上記リンク先の何番のルート通ったかって分かりますよね?
    (前提として、HTTP圧縮なしかつネットワーク改ざんなしとしてです。他にもありえなさそうな条件はない前提で考えるとして)
    観点としては、今回のケースですと、判定条件というより、判定後の結果の保存方法だと思っています。
    (キャッシュファイルの中に、拡張子保存用の専用の領域があった気がしています。ファイル名とは別に。)



    >oshi_yoさん
    再現する環境でのネットワークのキャプチャ結果、前述(application/x-csv)の修正による再現有無があるとうれしいです。
    ③のリンク先を見ると、ファイルの中身も影響する場合があるようですが。。

    >たろままさん
    もし、見ている&分かればでよいのですが、再現していたときのダウンロードしたときの拡張子が「変わったのか」「くっついたのか」分かりますでしょうか?
    また、Content-Dispositionヘッダの有無、Content-Typeの値があるとうれしいです。

    2011年5月22日 4:34

すべての返信

  • > ヘッダ(Content-Disposition: )には、filename=xxx.csvとセットしていますが、

    attachment; filename=xxx.csv としていますか?

     

    2011年5月12日 12:50
  • はい。

    vb.netで開発していますが

    Response.ContentType = "application/octet-stream"
    Response.AddHeader("Content-Disposition", "attachment; filename=xxx.csv")

    としています。

    この現象はお客様環境で起こっていますが、弊社内のテストでは起こりません。

    違いといえばお客様環境ではサーバーにofficeをインストールしていない事ぐらいだと思います。

    マイクロソフトのサポートページから「ファイルのダウンロードダイアログで表示されるファイル名の命名規則」

    http://support.microsoft.com/kb/436153/ja

    を参考に弊社内クライアントPCのレジストリも調べましたが

    Content-Type が application/octet-streamの設定は存在しませんでした。

    お客様環境も調べてもらった方がよさそうですか?

     

    2011年5月13日 0:31
  • Content-Disposition: attachment; filenaame=xxx.csv

    のうち「filename」部分の綴りが違うとダウンロードダイアログは開くものの、ファイル名が定まらずURLを元にしたファイル名(xxx.aspxなど)になりそうですが。

    2011年5月13日 1:18
  • Content-Disposition: attachment; filenaame=xxx.csv

    のうち「filename」部分の綴りが違うとダウンロードダイアログは開くものの、ファイル名が定まらずURLを元にしたファイル名(xxx.aspxなど)になりそうですが。


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

    綴りは先ほど書いたとおりですので、合っていると思います。

    他に原因は考えられませんか?

    filename=xxx.csv としていますが filename="xxx.csv"とした方がいいのでしょうか?

    弊社環境ではfilename=xxx.csvでも正常に動いているので問題ないと思っているのですが。

     

    2011年5月13日 2:55
  • 私も同様の件で、調べておりました。

    Response.ContentType = "application/x-csv"

    とすると、正常に動作しました。

    参考にしたのは、下記のURLです。

    http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=12433&forum=12

    ご参考までに。

    2011年5月13日 4:48
  • 試しにクリーンインストールしたWindows 7上で実行してみましたが、CSVファイルになりました。Content-Typeは正しくはtext/csvですし、あまり関係なさそうには感じました。

    ただし、Windows XPで試したわけではないので、その部分に違いがあるのかもしれません。そして、たろままさんのおっしゃる通り誰も使わなさそうなてきとーなContent-Typeを指定すると動作するのかもしれません。(application/x-csvはExcelをインストールしてもレジストリ設定されません。)

    2011年5月13日 7:17
  • > Response.AddHeader("Content-Disposition", "attachment; filename=xxx.csv")
    >
    > としています。
    >
    > この現象はお客様環境で起こっていますが、弊社内のテストでは起こりません。

    そうであれば、「お客様環境」に問題がある以外に原因はないと思いますが。

    パケットキャプチャツールで、実際に受信している HTTP ヘッダがどうなっている
    か調べてみてはいかがですか?

     

    2011年5月13日 13:12
  • 再現しました(`・ω・´)。

    確認したのは次の3環境で1環境のみ再現しました。IE6のみです。
    ①XP SP2 & IE6 & Officeなし
    →再現する
    ②XP SP3 & IE7 & Officeなし
    →再現しない
    ③7  SP1 & IE9 & Officeあり
    →再現しない
     
     
     
    【【事象確認】】
    再現したとは、次の事象を指しています(長いです)。
     
    ・HTMLには次の記載
     
    <a href="test1.cgi">test1.cgi</a>
     
    ・test1.cgiへリクエストされるとヘッダ部は
     
    Content-type: application/octet-stream
    Content-Disposition: attachment; filename="aaa.csv"
     
    ボディ部は「a,b,c」という5バイトの応答をします。
     
     
    HTMLを表示し、現れるリンクtest1.cgiをダウンロードするために左クリックすると以下が表示されました。(とりあえず、”ダウンロード確認ダイアログ”と呼ぶことにします)
     

    注目したいのは、
    ・”アイコン画像”がHTMLのものになっている
    ・"種類"欄が「HTML Document」になっている。
    ・"名前"欄には「aaa.csv」と正しく表示されている。
    ことかと思います。 

    ”アイコン画像”、”種類”、”名前”欄のいずれも、後述の画面とは違い、ファイルの中身を変えても変わりませんでした(確認時はキャッシュは消しています)。 またリクエストする.cgiを.aspcという通常は存在しない拡張子にし、サーバの設定を.aspcをCGIとして動作させたとしても変わりませんでした。
    ※IE9ではこの画面は出ず、一新されています。 
     
     
    その後、「保存」ボタンを押すと次の画面が表示されました(一般に"ファイル保存ダイアログ"と呼んでいるもの)。
    注目したいのは、
    ・"ファイルの種類"欄が「テキスト文章」となっている。
    ・”ファイル名”欄が拡張子が出ていない
    かと思います。 
     
    ”ファイルの種類”については、csvのファイルの中身がHTMLっぽいものにしておくと「HTML Document」になりました。
    ”ファイル名”については 「フォルダオプション」で「登録されている拡張子を表示しない」となっているためでした、表示するようにすると表示されました。
    拡張子を表示しようとしまいと、そのまま保存したときの実際のファイル名は「テキスト文章」でも「HTML Document」でも「aaa.csv」になりました。
    ※なお、「フォルダオプション」の「ファイルの種類」欄には拡張子CSVの登録はありません。 
     
     
    【【ネット上を検索】】
    似たようなの事象として、以下がありました。
    IE8でも起きることがあるようです。
     
    商品情報CSVのダウンロードをすると、CSVの拡張子でHTMLがダウンロードされる
    http://xoops.ec-cube.net/modules/newbb/viewtopic.php?topic_id=7514&forum=11
     
    CSVが保存ダイアログでHTMLになる
    http://okwave.jp/qa/q6443040.html
     
     
     
    【【本当の問題点の確認】】
    書いてきたように、当方の環境では、実際に保存されるファイル名は正しく保存されていました。
    また、"ファイル保存ダイアログ”の”ファイル名”の拡張子は.csvでした。
     
    >ファイル保存ダイアログでは拡張子がHTML形式で表示されてしまいます。
    お客様環境で起こっているのは、
    「”ダウンロード確認ダイアログ”で、 "アイコン画像”と”種類”がHTMLのものが出ている」ではないでしょうか?
    ファイル保存ダイアログで拡張子がHTML形式で表示されるのではなく)
    以上について、ご確認ください。
     
    もし、ファイル名も正しくない場合は以下が参考になると思います。
    ファイルのダウンロードダイアログで表示されるファイル名の命名規則 
     
     
     
    【【・・・で】】
    >他に原因は考えられませんか?
     
    ようやく、ここから本題です。何か考えられる予想が欲しいとのことですね。
    問題が起きているのは「保存時のファイル名」ではなく「アイコン画像」と「種類」という前提で話を進めると、
     
    最初は単に、次のようなことが影響していると思っていました。
    http://www.atmarkit.co.jp/fcoding/articles/webapp/02/webapp02a.html
    ①「拡張子ではなく、内容によってファイルを開くこと」の設定
    ②URLの拡張子
    ③IE以外のアプリケーションの設定
     
    例えば、Proxy(*.pac)接続かどうかでゾーンが変わったため設定が変わり、sniffing動作が変わった結果起きたのではないかなどと予想していました。
     
    が、当方では、いずれも該当しないようでした。
    ①の設定の有り無しを変えてみましたが、アイコンの種類は変わりませんでした。
    ②の設定の変更(.cgiを.aspxにしたり)してみましたが、アイコンの種類はHTMLのものでした。
    ③については、そもそも再現確認用のクリーンな環境です。
    「フォルダオプション」の「ファイルの種類」にはcvsは登録されていません。「アプリケーションの追加と削除」 には、「Flash Player」「Fiddler2」「VMware tools」「Windows Installer」の4つのみです。
    HKCR\MIME\Database\Content Typeにはoctet-streamの登録はありません。
     
    ですので、IE6は素の動きで、octet-stream時にcsvをHTMLとして保存する動作(しかし拡張子は.csv)になっているようです。
    書いてきたように、当方で再現した環境とお客様環境ともにofficeが入っていませんが、同じofficeが入っていない環境でも再現しない環境がありました。
    2011年5月16日 15:34
  • (´・ω・`)さん、大変参考になります。ありがとうございます。

    お客様環境について更に詳細に情報を入手しましたのでお伝えいたします。

    ①OSバージョン情報

     ・WindowsXP Professional Version2002 ServicePack3

    ②InternetExprolerのバージョン情報

     ・Version6.0.29005512.xpsp._sp3_gdr.100427-1636

    ③エクスプローラのツール->フォルダオプションで拡張子「CSV」と「ファイルの種類」の紐付けが正しく行われている。

     ※クライアントにはofficeがインストールされています。

    ④ファイル保存ダイアログのアイコン画像、ファイルの種類、ファイル拡張子の全てがHTMLとなっている。(ファイル名:xxx.csv.htmlで保存される)

     

    たろままさんのアドバイスに従いソースの修正を行いました。

    >Response.ContentType = "application/x-csv"

    運用中はソースの入れ替えが行えないので直ぐには確認できない状況です。

    結果が分かりましたらこの場でご連絡させて頂きます。

    症状が改善されない場合はまた調査となります。

    新たな情報などございましたらご教授の程、宜しくお願いいたします。

     

    2011年5月17日 7:40
  • こういう原因調査って、詳しくなればなるほど、事象のみが記載されて、
    その後の考察が薄くなるケースがある気がしているので、少し書かせてください。


    つまり、「Content-Dispositionのfilenameが効いているけども、
    .htmlという拡張子が末尾に付与されてしまう」という問題だったのですね。


    この事象は、再現していませんね。


    >②InternetExprolerのバージョン情報
    > ・Version6.0.29005512.xpsp._sp3_gdr.100427-1636

    原因究明のため、IEのバージョン番号の構成についてどこかにありましたら、ご教授ください。

    この構成、つまりIE6かつOFFICE入っている環境って、まだわりとあると思っています。
    どなかた確認された方はいませんかね?
    要は、この環境の場合、必ず再現するのかそうでないのかです。


    >Response.ContentType = "application/x-csv"

    実際に手元の環境でも”アイコン画像”が変わることは確認していますし、別に対処内容についてとやかく言うつもりはありませんが、この対処がどのようなケースで有効かの根拠が若干気になっています。

    apacheのデフォルトの設定では、text/csvですねぇ。
    http://ja.wikipedia.org/wiki/Comma-Separated_Values

    無知で申し訳ないのですが、「application/x-csv」って技術的な根拠ってありそうですかね。
    もともとの「application/octet-stream」をcsvに適用は微妙かもとは思っていますが。

    2011年5月20日 14:32
  • Excel がインストールされている環境の HKCR に登録される .csv の MIME Type は application/vnd.ms-excel ですね。

    サーバーからこのMIME Type を返すとどうなるのでしょうか。

    また MIME Sniffing が影響している可能性が考えられますから、以下の KB の WORKAROUND にある設定を試すと動作に変化が出るかもしれません。

    http://support.microsoft.com/kb/925832/en-us

     


    hebikuzure
    2011年5月21日 3:13
    モデレータ
  • IE6 (IE Tester の), IE8, IE9 で試してみましたが、拡張子が
    htm になるのが再現できたのは、ヘッダが以下のときのみでした。

    Content-Type: text/html
    Content-Disposition: attachment; filename=

    (注)上記で、Content-Type: text/html となっていますが、プロ
    グラムで HttpResponse.ContentType を指定しない場合 IIS
    が Content-Type: text/html を追加します。

    Content-Disposition ヘッダで、拡張子は正しく指定しているとの
    ことですが、途中にプロキシなどがあって、ヘッダを書き換えてい
    るというようなことはないでしょうか?

    くどいようですが、パケットキャプチャツールで、実際に問題の PC
    が受信している HTTP ヘッダがどうなっているか調べてみてはいかが
    ですか。


    以下補足

    当方で試した限りでは、参考にされていたマイクロソフトのサポート
    ページ(下記)に書いてあった通りの結果になりました。

    ファイルのダウンロードダイアログで表示されるファイル名の命名規則
    http://support.microsoft.com/kb/436153/ja

    即ち、「Content-Disposition: ヘッダが存在する場合は、filename パ
    ラメータで設定されたファイル名が利用されます。」ということです。

    サポートページには書いてないですが、Content-Disposition: ヘッダ
    でファイル名が指定してあれば、Content-Type: の指定は無視されます。

    2 番目の「HTTP レスポンス内に存在する、送られてきた Content-Type
    が、レジストリの HKEY_CLASS_ROOT\MIME\Database\Content Type 以下
    に存在するかどうか・・・」というのは、Content-Disposition: ヘッダ
    の filename パラメータにファイル名の指定がない場合に限るようです。

    具体的な例としては、ヘッダが以下のような場合で、この場合は拡張子
    が xls に書き換えられます。

    Content-Type: application/vnd.ms-excel
    Content-Disposition: attachment; filename=

    ご参考までに検証に使ったコードをアップしておきます。aspx ページは
    以下の URL でアクセスできますので、興味があれば試してみてください

    http://surferonwww.info/Test/csvdownloadtest.aspx


    aspx ページ (CsvDownloadTest.aspx)

    <%@ Page Language="C#" %>

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <script

    </script>

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:HyperLink ID="HyperLink1"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=1">
                filename="", ContentType=""
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink2"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=2">
                filename="", ContentType="application/octet-stream"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink3"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=3">
                filename="test.csv", ContentType="application/octet-stream"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink4"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=4">
                filename="test.csv", ContentType="text/csv"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink5"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=5">
                filename="test.csv", ContentType="application/vnd.ms-excel"
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink6"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=6">
                filename="test.csv", ContentType=""
            </asp:HyperLink>
            <br />
            <asp:HyperLink ID="HyperLink7"
                runat="server"
                NavigateUrl="~/Test/CsvDownloadHandler.ashx?type=7">
                filename="", ContentType="application/vnd.ms-excel"
            </asp:HyperLink>
        </div>
        </form>
    </body>
    </html>

     

    HTTP ハンドラ (CsvDownloadHandler.ashx)

    <%@ WebHandler Language="C#" Class="CsvDownloadHandler" %>

    using System;
    using System.Web;
    using System.Text;

    public class CsvDownloadHandler : IHttpHandler {
       
        public void ProcessRequest (HttpContext context)
        {
            string type = context.Request.QueryString["type"];
            switch (type)
            {
                case "1":
                    SetHeader(context, String.Empty, String.Empty);
                    break;
                case "2":
                    SetHeader(context, String.Empty, "application/octet-stream");
                    break;
                case "3":
                    SetHeader(context, "test.csv", "application/octet-stream");
                    break;
                case "4":
                    SetHeader(context, "test.csv", "text/csv");
                    break;
                case "5":
                    SetHeader(context, "test.csv", "application/vnd.ms-excel");
                    break;
                case "6":
                    SetHeader(context, "test.csv", String.Empty);
                    break;
                case "7":
                    SetHeader(context, String.Empty, "application/vnd.ms-excel");
                    break;
                default:
                    return;               
            }
           
            Encoding enc = Encoding.GetEncoding("shift_jis");
            string csvString = GetCsvString();
            context.Response.BinaryWrite(enc.GetBytes(csvString));
            context.Response.End();
        }
       
        protected void SetHeader(HttpContext context, string name, string type)
        {
            context.Response.AppendHeader("Content-Disposition",
                "attachment; filename=" + name);

            if (!String.IsNullOrEmpty(type))
            {
                context.Response.ContentType = type;
            }

            context.Response.Cache.VaryByHeaders["Accept-Encoding"] = true;
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.Response.Cache.SetExpires(DateTime.Now.ToUniversalTime());
            context.Response.Cache.SetMaxAge(new TimeSpan(0, 0, 0, 0));
            context.Response.AppendHeader("Pragma", "no-cache");
        }

        protected string GetCsvString()
        {
            string text = "a,b,c\nあ,い,う\n";
            return text;
        }
       
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

    }

     

    2011年5月21日 8:00
  • MIME Sniffing、実は影響していないと思うようになりました。(理由は後述)

    ネットワーク、Office、IEの切り分けは出来ていませんが、
    ダイアログを出す時点で拡張子(シェル拡張?)ハンドラ側でファイル名を正規化出来る仕組みってあるんですっけ?

    あとはおっしゃるようにProxy、Office、HTTP圧縮、SSL(cache周り)でしょうか。

    Mimeハンドラ動作時は、拡張子は入れ替わる(後ろに加わるではなく)という認識ですが、
    Officeは拡張子を後ろにくっつける印象を受けているため、Officeかなという気がしています。
    officeかどうかはどうでもよいとして、「くっつく」のか、「入れ替わる」かの違いは、結構重要だと思っています。
    sniffingするしないに関わらず、どちらかじゃないとおかしいですよね。「入れ替わる」方が正解なのでは。
    (ネットワークかどうかの確認は取りたいのは山々ですが、)。


    >SurferOnWwwさんからの引用
    >拡張子が xls に書き換えられます。
    「書き換えられる」のですね(Dispositionヘッダなし時)。「追加」されるではなく。


    以下、「>」は引用、「→」が思ったことです。(特に③、⑨が注目です)


    ■Content-Dispositionありでもファイル名は変更されるよ派
    ①IE6 でダウンロードする際、正しいファイル名が得られない現象
    http://d.hatena.ne.jp/e-kuroda/20070818/1187446917
    →とりあえず関係するのは前半部分だと思います。

    ②Internet Explorer 6 でダウンロード ダイアログに正しいファイル名が表示されない
    http://support.microsoft.com/kb/939251/ja
    >HTTP 圧縮を使用する環境では、Content-Disposition ヘッダーで指定されたファイル名は使われず、URL で指定した "test.asp" がファイル名として表示されます。
    →aspのようなので、拡張子が.csv.htmlになっている以上、ファイル名は使われているはず。Content-Encodingヘッダは避けた方がよさそうです。IE8,9でも同様の現象かは気になります。

    ③[IE] ファイルのダウンロードで、IEが.xmlという拡張子を自動で付与しちゃう
    http://cast-a-spell.at.webry.info/200803/article_10.html
    →拡張子が追加で付与されるケースと、入れ替わるケースの2つが書かれている気がしています。
    上記にも書きましたが、以下の認識です。
    ●拡張子が追加で付与
    未知の”何か” → 条件としてファイルの中身の記載もありましたので、sniffingも関係していました。(条件がこのサイトどおりであれば、ネットワークの可能性もほぼ消えそうです)
    ●拡張子入れ替わり:mime sniffing
      これは、単に、Content-Dispositionヘッダが付与されないパターンのケースなので、妥当&今回の件には関係なしと考えています。SurferOnWwwさんの試験結果と同じ。

    →たまたまでしょうけど、驚くのが、後述の⑨番のリンクの記載の中で、ちょうど"text/plain"と"octet-stream"というmime-sniffing処理の判定の中で特別視するものでは再現している模様。

    ④余分なファイルの拡張子がダウンロードされたファイルに追加します。
    http://support.microsoft.com/kb/231755/ja
    > Windows に登録されていないファイルの種類に発生することができます
    →Internet Explorer 5.0の話でIE6でも有効かは不明。Content-Dispositionなしの場合の話かなこれは。

    ⑤Office 2007
    修正: ファイルを保存するとファイル名拡張子が追加される
    http://office.microsoft.com/ja-jp/powerpoint-help/HP001165938.aspx
    →この辺が動作する条件であれば、現象は納得なのですが。

     

    ■Content-Dispositionあり時はファイル名は変更されないよ派
    ⑥Handling MIME Types in Internet Explorer
    http://msdn.microsoft.com/en-us/library/ms775148(v=VS.85).aspx
    >If the file is marked as "content-disposition=attachment" in the HTTP header, Internet Explorer treats the file name from the URL as final and does not rename it before placing it in the cache.
    →キャッシュにおく前は、ファイル名の変更はしない模様。
    じゃぁダイアログにはその名前がそのまま出るの?

    ⑦イベント 1021 - MIME 処理制限
    http://technet.microsoft.com/ja-jp/library/cc749557(WS.10).aspx
    >These changes do not affect cases where the file uses a Content-Disposition: attachment HTTP header.
    →Content-Disposition: attachmentを指定していれば、拡張子変更のロジックは動作しない。
    Applies To: Windows 7, Windows Vistaなページですが、2003SP1のサイトでも同じ内容なのでXP SP3も同じはず。
    →Mimeハンドラをスキップすることは分かりましたが、拡張子ハンドラは動作するとのこと。

    ⑧IE content-type logic - IEBlog
    http://blogs.msdn.com/b/ie/archive/2005/02/01/364581.aspx
    >Mimesniffing doesn't mean that there is no way for a server to control how a file is handled. <Content-disposition: attachment; filename="filename.ext"> header enables a server to do precisely that. With this however, IE makes sure that the user gets prompted with the file type information (based on the extension specified by the server here) before the file is opened/saved.
    →おそらく、もろもろの元ネタ。

    ⑨MIME Type Detection in Internet Explorer
    http://msdn.microsoft.com/en-us/library/ms775147(v=VS.85).aspx
    →Mimeハンドラ(FindMimeFromData)の動作があります。
    この辺の"text/plain"と"application/octet-stream"時の分岐の一部のルートに落ちたケースじゃないでしょうかね。
    英語得意な方であれば、上記リンク先の何番のルート通ったかって分かりますよね?
    (前提として、HTTP圧縮なしかつネットワーク改ざんなしとしてです。他にもありえなさそうな条件はない前提で考えるとして)
    観点としては、今回のケースですと、判定条件というより、判定後の結果の保存方法だと思っています。
    (キャッシュファイルの中に、拡張子保存用の専用の領域があった気がしています。ファイル名とは別に。)



    >oshi_yoさん
    再現する環境でのネットワークのキャプチャ結果、前述(application/x-csv)の修正による再現有無があるとうれしいです。
    ③のリンク先を見ると、ファイルの中身も影響する場合があるようですが。。

    >たろままさん
    もし、見ている&分かればでよいのですが、再現していたときのダウンロードしたときの拡張子が「変わったのか」「くっついたのか」分かりますでしょうか?
    また、Content-Dispositionヘッダの有無、Content-Typeの値があるとうれしいです。

    2011年5月22日 4:34
  • お客様より、修正後の動作確認が取れましたのでご報告いたします。


    ・保存ダイアログの表示は今までと同じ。(HTML)

    ・保存するとCSVで保存される。


    ということで、運用に問題なしということで対応完了の承認を頂きました。

    皆様おっしゃられるとおり、本当の原因究明とは行きませんでしたが

    対応工数的なこともあり、これで調査終了といたします。

    皆様のご協力に感謝いたします。


    最後に(`・ω・´)さんのご質問への回答です。

     ⇒ 実はお客様先は間に1社挟んでいまして、直接のお願いは出来ない状態です。
       前述の通り対応完了の承認も頂きましたので、キャプチャ等はお願いし辛い状況です。
       申し訳有りませんが、入手できません。

     

    ここで皆様からご教授いただいたことは大変参考になりました。

    今後の開発に役立てたいと思います。

    ありがとうございました。

     

     

    2011年5月26日 7:09
  • oshi_yo さん、

    こんにちは。
    フォーラム オペレーターの服部 清次です。

    いったん調査の終了を決められたとのことで、ご報告ありがとうございます。
    今回は残念ながら原因の究明には至りませんでしたが、参考情報として、確認ポイントや検証結果を提供してくださった方々の
    投稿内容を役立てていただけるのではないかと思いましたので、お礼の意味も込めて、私の方で [回答としてマーク] させて
    いただきました。

    また何か困ったことなどがありましたら、ぜひ MSDN/TechNet フォーラムをご利用ください。
    今後とも、よろしくお願いします!
    それでは、また。


    __________________________________________________
    日本マイクロソフト株式会社 フォーラム オペレーター 服部 清次


    (追記)
    [回答としてマーク] のチェックが付いた後でも返信することは可能ですので、関連情報をお持ちの方や新しい情報を得られた方が
    いらっしゃいましたら、お気軽にご投稿ください。



    2011年5月27日 4:52
    モデレータ