久しぶりの技術ネタ。HTTPレスポンスヘッダの[Content-Disposition]について、Safariでの日本語文字化け対策など。

昨今では、ブラウザが以前のようにIENetscape2社だけだった・・っと言っても、これらに対応するWebアプリケーションを作るのは大変だったわけだが、現在は、IEFireFoxGoogleChromeSafariOpera・・・って感じで、5種類のブラウザに対応しなければならないと言う悲劇があり、まあ大変ってわけだ。
描画系は、IE6やIE7が他のブラウザと違い独自臭がぷんぷんするわけだが、それ以外のブラウザIE8、FireFodx、GoogleChromeSafariは、まあ、大体良く似ている感じである。
Javascript系は、IE系と、FireFoxGoogleChromeOperaと、Safariとなっており、大まかに分けると、大体3つのグループに分かれる・・・って言っても、細かく言えばFireFoxGoogleChromeOperaも、微妙に違うわけなのだが、まあ他のIE系、Safariと比べると、互換性があるわけだから、こんな感じでよしとしよう。
・・・・・・
まあ、こんな感じで現在のWebアプリケーションを作っていくことは、まあ面倒であることには代わりが無いのだが、まとめると、商用OSを提供している会社のブラウザと、それ以外のブラウザとでは、何だか相反するものがあるのか?昨今GoogleもアンドロイドとかクロームOSとか、OS部門に手を染めつつあるので、今後GoogleChromeも仕様が剥離していくのか?まあ、それはそれとして、長々と記述した内容はおいといて、本題に入りたいと思う。
・・・・・・
Webアプリケーションなどで、URL名以外で、情報を返却させたい場合、HTTPレスポンスヘッダに

Content-Disposition: attachment; filename="hogehoge.txt"

のように、情報を追加することで、別名でブラウザからコンテンツをダウンロードできるようになるわけで、これを使わない場合、一旦CGIなどにリダイレクト[Location]などで、ダウンロードさせたいファイル名をURLに含めて、処理していたわけで、これらの実装って別途面倒だったりしたわけだが、[Content-Disposition]によって、かなり実装が楽だったりしたわけで、ファイルのダウンロードを促す場合は、このHTTPレスポンスヘッダを利用したりするわけだ。
しかし、この[Content-Disposition]は、本来のHTTPヘッダルールにあるわけではなく、Mailの添付ファイルのときのヘッダであり、これがいつの間にか、既存のブラウザなどでは、普通に扱えるようになったわけなのだが、元々HTTPヘッダルールではないためか、根本ルールがないってことで、各ブラウザの振る舞いは、マルチバイト文字など、結構違いがあるわけだ。
って言うのは、元々ブラウザってのは日本製ではなく、外国のものであり、日本語などのマルチバイト系を扱うのは、以前より、色んなところで文字化けがあったり、URLEncodeしても、それが対応されていないと、そのまんま文字が処理対象となったり(表示されたり)、その結果、日本語に変換されなかったりと、ブラウザと文字化けってのはよくある話であり、面倒なわけである。
そして、この文字化けの件は[Content-Disposition]で、結構面倒な話となり、特にSafariなどは、ググってみても、先ほど書いた、昔のダウンロード方法[Location]でリダイレクトしてダウンロードする方法しかないと言うわけで、まあこんな感じで各ブラウザの挙動は、ばらばらであり、面倒である。
・・・ってことで、ちょっと仕事でダウンロードファイルの日本語名が文字化けするから直せと、指示があったので、各ブラウザで問題ない変換方法が大体分かったので、下記に、各ブラウザで処理可能な[Content-Disposition]の日本語文字化け対策方法をメモとして残す。
Javaで記載。headerオブジェクトは、HttpHeader的オブジェクトに追加するようなイメージ。

【IE6,IE7,IE8】
header.set( "Content-Disposition",
"attachment; filename=\""+URLEncoder.encode( name,"UTF8" )+"\"" ) ;
header.set( "Content-Type",mimeType+"; charset=utf-8" ) ;
※返却対象の名前内にスペースがある場合、プラスに変換するURLEncoder系は、表示名がスペースがプラスになってしまうので、自前でURLEncoderを作るのをすすめる。

【Opera11.5】
header.set( "Content-Disposition",
"attachment; filename*=utf-8'ja'"+URLEncoder.encode( name,"UTF8" ) ) ;
header.set( "Content-Type",mimeType+"; charset=utf-8" ) ;
※別にIEの対応と同じでも、正常に処理できるわけだが、こちらの方が、本来は正しい記述なので、こちらを採用。

Safari(win)4.05,Safari(win)5.1】
header.set( "Content-Disposition","attachment; filename=\""+name+"\"" ) ;
header.set( "Content-Type",mimeType+"; charset=utf-8" ) ;
・・・・・
※【必須】HttpレスポンスヘッダをUTF8でバイナリ変換する
 言い換えれば、HttpレスポンスヘッダをUTF8で返却する

【その他:FireFox3,4,5とGoogleChrome13.0.782.24 m】
header.set( "Content-Disposition",
"attachment; filename=\"=?utf-8?B?"+Base64.encode( name,"UTF8" )+"?=\"" ) ;
header.set( "Content-Type",mimeType+"; charset=utf-8" ) ;

※一応説明すれば、\マークで区切っている所は、¥半角文字ね。
 
こんな感じの処理で、日本語ファイル名が解決可能。ただし、Safariは、Windows版の4.01、5.1のバージョンで試しただけなので、Macは持っていないので、それらで試したわけではないので、何ともいえないのだが、私が成功したSafari対応では、単純に日本語文字をURLEncodeとかせずそのまま貼り付ける、そして、HTTPレスポンスヘッダを本来はISO-8859_1とかで変換するのではなく、これをUTF8で変換して、Safariに送信してみると、うまくいったわけで、それ以外の方法(URLEncodeで返却、Base64で返却のいずれかを試してみても、そのままの文字で処理される)ではうまく処理できなかった。
・・・・・・
日本語(マルチバイト)とコンピューターは、相反するものがあるのか、まあ、この辺面倒なことばかりで、ふと魔がさして、お客様に「仕様です」って言いたくなることもあるが、まあ金を出しているお客様に、こんなに面倒なんですって、説明するわけにも、理解しづらいだろし、凄く簡単なんでしょ?みたいに思っているわけで、そして苦労して、修正しても、あまりありがたがられないわけで、まあ、この辺の対応はヤルセナイ気持ちになってしまう。
・・・・・・
まあ、この辺面倒だが、一度対応すれば、それをライブラリ化して使えるわけで、この辺もネットが無ければ、調べるのに偉く苦労しただろうし、一応Safari対応もできたわけだから、短期間で調べれたネットに、感謝の気持ちを込めて、メモとした次第である。