Unicodeのダウンロード名が文字化けするとき:filenameとfilename*の違い

Content-DispositionでUnicodeのファイル名を送る方法を解説します。ASCIIのfilename、UTF-8のfilename*、パーセント符号化、優先順位、安全な受信処理をRFC 6266とRFC 8187に沿って整理します。

開発HTTPエンコーディング

サーバーが보고서.pdfを意図したのに、受信側に提示された名前が異なる、または文字化けしているなら、Content-Dispositionレスポンスヘッダーを確認します。このヘッダーはレスポンスの扱い方と保存名の候補を伝えます。ASCII以外の名前をplain filenameへ直接入れる方法は失敗することがあります。RFC 6266は互換性のため、filenameと拡張パラメーターfilename*の両方を送るよう勧めています。

attachmentとファイル名は別の情報

attachmentはメディアタイプに応じた通常の処理ではなく、ローカル保存を促すdisposition typeです。filenameとfilename*は保存名を組み立てる情報です。

Content-Disposition: attachment; filename="report.pdf"; filename*=UTF-8''%EB%B3%B4%EA%B3%A0%EC%84%9C.pdf

filename="report.pdf"は拡張構文を理解しない古い受信側向けのASCII代替名です。filename*には本来の名前보고서.pdfが入っています。両方がある場合、RFC 6266はfilename*を理解する受信側に、そちらを選んでfilenameを無視するよう推奨しています。互換性に関する助言に従い、代替名を先に置いています。

同じパラメーター名を二度使うとフィールド値は無効です。複数のfilename*に言語別の名前を並べる形式ではありません。言語部分は任意で、ファイル名では用途が限られるため、この例では空にしています。

アスタリスク付きの値にはUTF-8のバイトを入れる

RFC 6266はこの構文についてRFC 5987を参照していますが、後にRFC 8187がRFC 5987を廃止しました。そのため、現在の符号化構文はRFC 8187に従います。拡張値は文字エンコーディング'言語'値という構造です。生成側はUTF-8を使わなければならず、受信側もUTF-8をサポートしなければなりません。보고서.pdfをUTF-8にすると次のバイト列になります。

EB B3 B4 EA B3 A0 EC 84 9C 2E 70 64 66

許可されたASCII文字はそのまま残し、それ以外のオクテットを%と2桁の16進数で表します。

filename*=UTF-8''%EB%B3%B4%EA%B3%A0%EC%84%9C.pdf

最初のアポストロフィーより前のUTF-8は必須の文字エンコーディングです。二つのアポストロフィーの間は任意の言語タグで、ここでは空です。空白はattr-charに含まれないため%20にします。受信側は16進数の大文字と小文字の両方を解釈できる必要がありますが、表記は統一した方が読みやすくなります。

これはURL全体をエンコードする意味ではありません。UTF-8のオクテットをパーセント表記にする点はURLエンコードと共通しますが、ここで適用されるのはHTTPヘッダーパラメーターの構文です。

受け取った名前は命令ではなく候補

RFC 6266は、受信側がファイル名を参考情報としてのみ扱うべきだと強調しています。../../etc/passwdのようにパスを含む名前でも、許可された場所以外へ書き込んではいけません。\または/で区切られた最後の部分だけを採用するのは一つの防御方法です。受信側がメディアタイプの判定を拡張子に頼る場合は、その拡張子が安全であることを必ず確認し、できればレスポンスのメディアタイプと一致させます。制御文字、前後の空白、.、..、デバイス名など、ファイルシステムやシェルで特別な意味を持つ名前は取り除くか置き換えるべきです。

サーバー側の実用的な基本形は明快です。ASCIIのfilenameを先に置き、本来の名前をUTF-8に変換したfilename*を続けます。受信側では、どちらを採用してもパスと拡張子を検証します。plain filenameにUTF-8文字を直接入れた場合に各ブラウザーがどう復元するかは、このRFC群が保証する動作ではなく、本記事の対象外です。

ZIPのファイル名エンコーディングでは、ダウンロード後に圧縮ファイル内部の名前が文字化けする別の問題を扱っています。

参照仕様

文書のステータスと正誤表を含め、2026年10月5日に確認しました。

ブログへ