※当サイトの記事には、広告・プロモーションが含まれます。

multipart/form-dataで日本語のファイル名が文字化けするのは仕様らしい

gigazine.net

ザキルリン氏によると、認知負荷を一言で言うと「開発者がタスクを完了するためにどれだけ考える必要があるか」になるとのこと。

開発者が速攻でプロジェクトを片付けるのに重要なポイント「認知負荷」とは? - GIGAZINE

平均的な開発者は、コードの変数の値、制御フロー ロジック、呼び出しシーケンスなどの要素を平均して4つほど頭に入れて作業を進めることができますが、この基準を超えた認知負荷が発生すると、途端にコードを読むのが難しくなります。

開発者が速攻でプロジェクトを片付けるのに重要なポイント「認知負荷」とは? - GIGAZINE

⇧ これ以外にも、外部ライブラリの使い方がドキュメントに無い場合とかが困るんよね...

「ファインダビリティ(Findability)」が無いと、「考える」までに至るのに不毛な時間を浪費させられるので、最悪なんよね...

multipart/form-dataで日本語のファイル名が文字化けするのは仕様らしい

2か月前ぐらいになるのだけど、久々に、ファイルアップロード機能の実装をしていた時に、デバッグ実行でサーバーサイド側に渡ってきた情報を確認していたら、日本語のファイル名が文字化けしてることに気付きました。

どうやら、

qiita.com

詳細

multipart/form-dataはデータ送信時のデフォルトcharsetはISO-8859-1になるようです。multipart/form-data, what is the default charset for fields? の回答が参考になりました。ISO-8859-1は日本語がないため、この段階で文字化けが発生します。

multipart/form-dataで、日本語ファイル名が文字化けする(API Gateway, Lambda構成) #lambda - Qiita

そのためAPI gatewayにデータを送信する前に日本語ファイル名をencodeURIを使い、ISO-8859-1でエンコードされる前にUTF-8エンコードし、サーバー側で受け取ったデータをdecodeURIでデコードすることで文字化けなくファイル名を取得できました。

multipart/form-dataで、日本語ファイル名が文字化けする(API Gateway, Lambda構成) #lambda - Qiita

⇧ 上記サイト様によりますと、デフォルトだとデータ送信時は、つまり、クライアント側からは、ISO-8859-1でしか送信できないと。

で、Postmanのissueによると、

github.com

⇧ 何やら、HTTPの仕様らしいという話が出ている。

で、残念ながら、フロントエンド側のHTTPクライアントでメジャーっぽいであろう、

  • fetch API
  • axios

のいずれのライブラリについても、対応はしてくれていないっぽいので、自力で対応するしかないっぽい。

ネットの情報を漁った感じでは、

stackoverflow.com

⇧ stackoverflowで質問してる方がおられましたが、質問と回答が噛み合っていないんですよね...

ちなみに、

qiita.com

⇧ JavaのHTTPクライアントのライブラリが対応しているという話があるのだけど、送信先での確認について言及されていないので、本当に文字化け解消できているのか分からない...

だって、HTTPの仕様であるなら、どのプログラミング言語のHTTPクライアントのライブラリであろうと、リクエスト時にISO-8859-1でしか送信できないのであれば、文字化けされた状態で送信先に届くはずだものね...

対応方法の整理

対応方法としては、

  1. クライアント側、サーバーサイド側の両方で対応する
    → クライアント側でエンコードし、サーバーサイド側でデコードする
  2. サーバーサイド側だけで対応する
    → サーバーサイド側で、文字列をISO-8859-1のバイトとして取得後、UTF-8の文字列に生成し直す。

のどちらかになる感じらしい。

残念ながら、クライアント側だけで対応する術は無いっぽい...

クライアント側は送信元なので、

No 送信元(クライアント側) 送信先(サーバーサイド側)
1 フロントエンド サーバーサイド
2 サーバーサイド サーバーサイド

⇧ というパターンが有り得るとは思うので、「送信元(クライアント側)」のプログラミング言語は様々になるとは言え、HTTPクライアントのライブラリが対応していない限り、multipart/form-dataにおいては日本語のファイル名が漏れなく文字化けするということなんですかね?

HTTPの仕様で、ISO-8859-1以外の文字コードに対応していないのが問題らしいので、

ISO 8859-1(より正式にはISO/IEC 8859-1)はISO/IEC 8859の第一部であり、ラテンアルファベットの文字コード標準である。よりくだけた言い方ではLatin-1と呼ばれる。最初はISOによって開発されたが、後にISOとIECによって合同で保守されている。

https://ja.wikipedia.org/wiki/ISO/IEC_8859-1

網羅範囲

ISO 8859-1が符号化しているものは「ラテン文字第1部」と呼ばれ、ラテン用字系の191文字からなる。この文字エンコーディングはアメリカ州、西ヨーロッパ、オセアニア、およびアフリカの多くで使われている。東アジア言語のほとんどの標準ローマ字表記でも広く使われている。

https://ja.wikipedia.org/wiki/ISO/IEC_8859-1

符号表

ISO/IEC 8859-1によって符号化される191文字はすべて「図形」(graphic。制御符号でない文字を表すISOの用語)であり、かつほとんどのWebブラウザと互換性があるため、以下の表でグリフとして示すことができる。

https://ja.wikipedia.org/wiki/ISO/IEC_8859-1

⇧ 上記で表現できない文字は問答無用で文字化けすることになるということなんですかね。

となると、英語以外の言語は全滅な気がするんだが...

Spring Boot 3.3.4とかそこそこ新しいバージョンを利用していたから、Spring Boot側で良しなに処理してくれるものだと思っていたのだけど、全くそんなことが無いというね...

Spring Web MVCも最新のバージョンだと思うから、Servletとかも最新になっているとは思うんだが...

で、

qiita.com

まとめ

JavaServletで文字化けするのでフィルタを書くのは昔はあるあるだったのですが、まさか現代でもやるとは思わず少し嵌りました。ファイルのアップロードは相変わらず罠がいっぱいですね。
RFCとは違うとはいえUTF-8はASCII領域は同じコードだし、UTF-8がデフォルトでも良い気はします。

QuarkusでMultipart Requestの文字化け対策 #Java - Qiita

⇧ 上記サイト様によりますと、新参者であるQuarkusでも対応されていないらしい...

Spring Web MVCとか利用している場合は、

typea.info

⇧ 一旦、「ISO-8859-1」のencodingとしてバイトに変換した後に、「UTF-8」のencodingで文字列を生成し直すことで、ファイル名の文字化けは解消できますと。

ファイルがテキストファイルだった場合に、ファイルの中身は文字化けの影響が無いのかな?

何と言うか、Spring Boot 3系の問題なのかと疑っていたのだけど、そもそも、Spring Boot 2系でも対応されていなかったっぽい哀しみ...

Javaは、枯れた技術であるはずなのに、未だにファイル系の処理がイケてないんかね...

毎度モヤモヤ感が半端ない…

今回はこのへんで。

 

Â