0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HTTPリクエストしたファイル名が文字化けしてしまう

Posted at

事象

  • ファイル名に日本語を含む(概要.md)ファイルを"Content-Type": "multipart/form-data; charset=UTF-8"で HTTP 送信すると、サーバー側でリクエストを受け取ると、ファイル名 が文字化けしてしまった
    • 正しいファイル名:概要.md
    • 文字化けされたファイル名:æ¦è¦.md
  • しかし、ファイルの内容(markdown の中身)自体は文字化けしていなかった

2024-05-05-13-17-03.png

なぜ ファイル名 は文字化けして、ファイルの内容は文字化けしなかったか?

  • ファイル名 は、HTTP ヘッダーに含まれて、
  • ファイル の内容は、HTTP ボディに含まれる

    という違いがあります。
HTTP ヘッダー HTTP ボディ
扱えるもの - ASCII 文字のみ - 任意のデータ
- エンコード方式

HTTP ヘッダー

扱えるデータは ASCII 文字のみです。

日本語は非 ASCII 文字なので、これが原因で文字化けが発生しました。

HTTP ボディと違ってエンコードはされません。

HTTP ボディ

HTTP ヘッダーと違って、HTTP ボディでは、テキストデータとエンコード方式を扱えます。※

データが HTTP リクエストのボディに含められる前に、エンコードされて、サーバーがリクエストを受信した後に、デコードされます。

つまり、HTTP ボディではエンコードとデコードが自動で処理されます

HTTP ヘッダと HTTP ボディでこのような違いがあるため、HTTP ヘッダでは文字化けが起こり、HTTP ボディでは文字化けが起こらない、ということが発生しました。

なお、デフォルトのエンコード方式は UTF-8 のようですが、header の Content-Type に明示的に charset=UTF-8 と指定することをおすすめします。

※バイナリデータ(画像、ビデオ、オーディオファイルなど)も扱えますが、ここではシンプルにするためテキストデータのみで説明しました。

問題の解決法

HTTP ヘッダでは ASCII 文字しか扱えないため、日本語などの非 ASCII 文字を ASCII 文字にエンコードする必要があります。

const encodedFilename = encodeURIComponent(file.name);

encodeURIComponent()は下の文字以外を「% + 2 桁の 16 進法」という形式に変換します。

A-Z a-z 0-9 - _ . ! ~ * ' ( )

すると、すべて ASCII 文字になります。

で、サーバー側でリクエストを受信したあとで、デコードします。

const decodedFilename = decodeURIComponent(req.file.originalname);

確認するとちゃんと日本語で表示されました。

2024-05-05-13-29-52.png

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?