Servletで日本語名のファイルをダウンロード

tomcat plugin

なんかものすごく忙しくて更新する暇が全く無い状態です・・・。

さて、今日は実際直面した問題をメモ代わりに書いておきます。あんまり日本語ファイル名を扱わないので忘れがちなので。

ダウンロード時にファイル名を指定する場合は、Content-Dispositionヘッダを使いますが、日本語の場合そのまま指定すると文字化けを起こしてしまいます。

しかもブラウザによって挙動が異なるという・・・。どうしたらいいのでしょう。

解決方法

まず、MS-IEでは「ファイルをダウンロードする ASP.NET Web ページで日本語ファイル名が文字化けする 」にあるように、以下のような仕様になっているようです。

Internet Explorerでは、Content-Disposition ヘッダが送信された場合、送られてきたコンテンツをそのままブラウザで開かずにファイルダウンロードダイアログを表示するようになっています。その際にこのヘッダの filename パラメータを利用している場合、このパラメータで渡されたファイル名をファイルの保存時の既定のファイル名にします。ただし、クライアントコンピュータのロケールを日本語にしている場合、Internet Explorer ではこのパラメータで渡された文字列 (ファイル名) を Shift-JIS でエンコードされているものとして処理します。

また、ASP.NET および .NET Framework では、構成ファイル globalization エントリ responseEncoding 属性の設定に関わらず、HTTP ヘッダを UTF-8 でエンコードして送信します。Internet Explorer では、UTF-8 でエンコードされたファイル名を Shift-JIS でエンコードされているものとして処理するため、ファイル名を正しく表示できません。

Content-Disposition ヘッダのパラメータの文字コードのエンコード方式に関しては、RFC2231 に基づくべきですが、現行の Internet Explorer はこのエンコード方式をサポートしていません。 RFC2231 につきましては、以下の URL をご参照ください。
RFC2231: MIME Parameter Value and Encoded Word Extensions: Character Sets, Languages, and Continuations
http://www.ietf.org/rfc/rfc2231.txt

上記によるとShift_JISでそのまま出力すればよいという感じで書かれていますが、日本語以外のマルチバイト文字も考慮するとUTF-8でいきたいところです。調べてみると、UTF-8をx-www-form-urlencodedすればOKのようです。

ただし、これはIEのみに対応した方法で、通常はRFC2231に対応した方法(MIMEエンコード)を行う必要があります。

if(request.getHeader("User-Agent").indexOf("MSIE") == -1)
    response.setHeader("Content-Disposition", "attachment; filename=" + MimeUtility.encodeWord(filename, "ISO-2022-JP", "B"));
else
    response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(filename, "UTF-8"));

コードにすると、まあこんな感じでしょうか。FirefoxとIEでしかチェックしていないので、OperaやSafariでは不明です。

また、IEの場合は文字化け以外にも、「256バイト以上のヘッダの場合にファイル名が切り捨てられる」とか「ファイル保存ダイアログが2回表示される」とか・・・問題が多いようです(パッチで修正されているものもありますが)。

LINEで送る
Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です