ダウンロードファイル名、文字化けとの格闘

結論:

ブラウザ判定のロジックを入れ込むことなく、 複数のブラウザにてダウンロードファイルの文字化けを避けたい場合は、 レスポンスヘッダに

Content-Disposition: attachment;
                     filename="ファイル名";
                     filename*=UTF-8''URLエンコーディングされたファイル名

上記のように設定しよう。 恐れることはない、filename*が有効なブラウザではfilename側は無視される。

RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)

以下、背景から試行錯誤の流れ。

seasar提供のResponseUtil.downloadを使用してファイルのダウンロードを試みる。

// fileName:ダウンロード時のファイル名(String)
// downloadFile:ダウンロード対象のファイル(File)
ResponseUtil.download(new String(fileName.getBytes("UTF-8"), "ISO-8859-1"),  new FileInputStream(downloadFile))

こんな感じで呼び出すも、IEでのダウンロード時に日本語ファイル名が文字化けする。(FireFoxとChoromeはOK)

色々調べたところContent-dispositionを設定してやればよいらしい。

browser - How to encode the filename parameter of Content-Disposition header in HTTP? - Stack Overflow

「なるほど、responseヘッダか!これで解決!」 と、意気揚々とアクションクラスにresponseをDIしてレスポンスヘッダを設定する。

...が、上手くいかない。 ResponseUtil.downloadの内部でContent-Disposition設定されていることに数分後に気付く。

という事は、元々の方法を模索する。 設定はされてるけど、IEだと化けるという事は、結局のところ引数(ファイル名)に難ありと判断。 引き続き情報を集めてみると、どうやらIEはURLエンコーディングした文字列だと上手く行くらしい。 (どこで見かけた情報か失念しました。。。) 早速試してみる。

引数を以下のように変更。

new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
↓
URLEncoder.encode(fileName, "UTF-8");

するとIEでも文字化けせずにダウンロードが出来た!

~Fin~

...が、FireFoxで化けることが判明 (URLエンコーディングされた文字列そのままでダウンロードしようとしてしまう)

これだからクロスブラウザ対応は嫌いだ!!

うーん、User-Agentからブラウザ判別する? とはいえ、User-Agentは変更される可能性もあるしなぁ。。。 (IE11の例もあるし・・・)

と、うなりながら情報を集めていると、最初に掲載したURLに気になる記述が。

filenameとは別にfilename*なんていうものがあるのか。。。 なるほど、文字セットやエンコードを指定したパラメータの設定ができるのね。

http://www.eonet.ne.jp/~h-hash/rfc_ja/rfc5987.ja.html

それでいて、場合によっては無視してくれる、と。

RFC 6266 - Use of the Content-Disposition Header Field in the Hypertext Transfer Protocol (HTTP)

うん、これでいこう。 という事で冒頭の結論へ。