HTML formタグのencTypeについて深掘りしてみる
はじめに
Web開発してると、必ずと言っていいほど登場するのがHTMLの<form>
タグ。ユーザーからの情報をサーバーに送る、基本中の基本ですよね。でも、テキストだけじゃなくファイルを送ろうとした途端、「あれ?なんか上手く送れないぞ…?」ってなった経験があり、記事を書くことにしました。
その原因、もしかしたら<form>
のencType
(エンクタイプ)属性の設定漏れや間違いかもしれません。
encType
って、普段はあまり意識しないかもしれないけど、実はフォーム、特にファイルアップロードの成否を左右する重要な影の立役者なんです。
この記事では、「なんとなく知ってる」かもしれないencType
属性について、基本からしっかり掘り下げていきます。それぞれの値が何をやっているのか、どう使い分けるのか、そしてファイルアップロードでなぜmultipart/form-data
が必須なのか等、調べたことを共有します。
encType
属性って、そもそも何? - データ送信の「梱包ルール」を決めるやつ
encType
属性は、フォームで入力されたデータがサーバーに送られるとき、どんな形式(ルール)で「梱包」して送るか を指定するための属性です。特に、method="post"
でフォームを送信するときに意味を持ちます。
ブラウザはフォームデータをHTTPリクエストのボディに詰めて送るんですが、そのままだとサーバーが正しく解釈できないことがあるんですね。そこで、事前に「こういうルールでデータを整形・梱包しますよ」と決めておく必要があります。そのルールを指定するのがencType
の役割です。
この梱包ルールが間違っていると、サーバー側で「荷解き」(デコード)がうまくできず、データが文字化けしたり、ファイルが正しく受け取れなかったりするわけです。
encType
の3つの顔 - それぞれの役割と使い方
encType
には、主に3つの指定方法があります。それぞれどんな性格で、どんな場面で活躍するのか見ていきましょう。
application/x-www-form-urlencoded
- デフォルト
1. -
これが基本、デフォルトです。
encType
を何も書かなければ、自動的にこれになります。 -
仕事内容:
- フォームのデータを「キー=値」のペアに変換。
- 英数字以外の文字や記号は、URLエンコードというルールで安全な形(スペースは
+
に、特殊文字は%xx
みたいに)変換します。 - 各ペアを
&
で繋げて、一本の文字列にして送り出します。 - 例:
username=Tanaka+Taro&memo=%E3%83%A1%E3%83%A2%E3%81%A7%E3%81%99
(「メモです」がエンコードされている)
-
得意なこと / 苦手なこと:
- 名前やメールアドレスみたいな、普通のテキストデータを送るのは得意。
- ファイル(画像とか)を送るのは苦手。 ファイルの中身までは送ってくれません。ファイル名くらいしか送れないんです。
multipart/form-data
- ファイル送信のヒーロー
2. - ファイルアップロードがあるなら、こいつの出番! 絶対に指定が必要です。
-
仕事内容:
- フォームデータを、いくつかの「パート」に分けて梱包します。まるで小包をいくつか作るイメージ。
- 各パートには「これは〇〇という名前のテキストデータです」「これは△△というファイル名の画像データです」といったラベル(ヘッダー情報)が付きます。
- テキストデータはそのまま、ファイルデータも中身をバイナリのまま、エンコードせずに梱包できます。
- パートとパートの間は、特別な区切り文字(boundary)で仕切られます。
-
得意なこと / 苦手なこと:
- テキストもファイルも、ごちゃ混ぜにして送れるのが最大の強み。
- ファイルアップロード機能を作るときは、指名必須の属性値です。これがないと始まりません。
text/plain
- ちょっとマイナーな正直者?
3. -
仕事内容:
- データをほとんどエンコードせず、見た目に近い形で送ります。スペースはスペースのまま、改行もそのまま。
- キーと値が
=
で結ばれ、各ペアが改行で区切られます。 - 例:
username=Yamada Hanako memo=テストメッセージ
-
得意なこと / 苦手なこと:
- 人間が見る分には、なんとなく分かりやすいかも…?
- でも、特殊文字の扱いが曖昧だったり、サーバー側で「これ、どこからどこまでが一つの値?」ってなりがち。バグの温床になりやすいので注意が必要です。
- 基本的にデバッグ用と考えた方が安全です。本番サービスで積極的に使う場面はほぼありません。ファイル送信も当然できません。
encType
を使ってみよう - コードで見る違い
実際にコードでどう書くか見てみましょう。encType
は<form>
タグに書きます。
application/x-www-form-urlencoded
(デフォルト) - テキストだけならこれでOK
<form action="/user/profile" method="post">
<label for="name">お名前:</label>
<input type="text" id="name" name="username"><br>
<label for="bio">自己紹介:</label>
<textarea id="bio" name="userbio"></textarea><br>
<button type="submit">更新</button>
</form>
👆 テキスト入力だけなら、特にencType
を意識する必要はありません。
multipart/form-data
- ファイルを送るなら必須!
<form action="/upload/image" method="post" enctype="multipart/form-data">
<label for="title">タイトル:</label>
<input type="text" id="title" name="image_title"><br>
<label for="img">画像ファイル:</label>
<input type="file" id="img" name="uploaded_image" accept="image/*"><br>
<button type="submit">アップロード</button>
</form>
text/plain
- (ほぼ)使わないけど一応…
<form action="/debug/formdata" method="post" enctype="text/plain">
<label for="debug_msg">デバッグメッセージ:</label>
<input type="text" id="debug_msg" name="debug_message"><br>
<button type="submit">送信 (デバッグ用)</button>
</form>
ユースケース - じゃあ、結局いつどれを選ぶの?
シンプルに考えましょう。
フォームで送りたいものは? | おすすめ encType
|
具体的な例 |
---|---|---|
テキストや選択肢だけ | application/x-www-form-urlencoded |
ログイン、検索、ユーザー設定、問い合わせフォーム、簡単なアンケートなど |
ファイル(画像、PDFなど)を含む場合 | multipart/form-data |
プロフィール画像変更、レポート提出、SNSへの写真投稿、ファイル共有機能など |
ちょっと生のデータを見てみたい(デバッグ) | text/plain |
サーバーに送られるデータ形式を一時的に確認したいとき(でも開発ツールの方が便利かも) |
判断フローは超簡単:
- あなたのフォームに
<input type="file">
はありますか?-
YES! → 迷わず
enctype="multipart/form-data"
をmethod="post"
と一緒に指定! -
NO! → 基本的に
encType
は書かなくてOK(デフォルトのapplication/x-www-form-urlencoded
で十分)。text/plain
は、よっぽどの理由がない限り忘れましょう。
-
YES! → 迷わず
encType
の裏側とデバッグのコツ
【もう一歩踏み込む】基本は上記の通りですが、もう少し知っておくと「なるほど!」となるポイントをいくつか。
1. 開発ツールでネットワークリクエストを覗いてみよう!
これが一番分かりやすいです。ChromeやFirefoxの開発者ツールを開いて、「ネットワーク」タブを見ながらフォームを送信してみてください。
-
application/x-www-form-urlencoded
だと、リクエストのContent-Type
ヘッダーがapplication/x-www-form-urlencoded
になり、「ペイロード」タブを見るとURLエンコードされたキー=値&キー=値
形式のデータが見えます。 -
multipart/form-data
だと、Content-Type
がmultipart/form-data; boundary=----WebKitFormBoundary...
のようになり、ペイロードを見ると、boundary
文字列で区切られたパートの中に、ファイル情報やファイルの中身(時にはバイナリで読めない形で)が見えるはずです。
この違いを実際に目で見ることで、「ああ、こういう風にデータが送られてるんだな」と実感できます。
2. サーバーサイドでの受け取り方が変わる!
送るデータの形式が違うということは、当然サーバー側での受け取り方(データの解釈方法)も変える必要があります。
-
application/x-www-form-urlencoded
のデータは、多くのWebフレームワーク(Node.jsのExpressならexpress.urlencoded()
ミドルウェア、PHPなら$_POST
変数など)が、特別な設定なしに簡単に扱えるようになっています。 -
multipart/form-data
のデータは、ファイルを含んでいる可能性があるため、専用の処理が必要です。例えばNode.js/Expressならmulter
のようなミドルウェア、PHPなら$_FILES
変数を使ってファイルデータを受け取ります。
サーバーサイドエンジニアは、フロントエンドの<form>
で指定されたencType
に合わせて、適切なデータ受け取り処理を実装しないといけません。もしフロントとサーバーで認識がズレていると、サーバー側で「データが空だぞ?」とか「ファイルが見当たらない!」といったエラーになるわけです。
encType
を制してフォームを制す!
まとめ - encType
属性は、フォームデータ送信の「梱包ルール」を決める大事なやつでした。
- テキストだけならデフォルトの
application/x-www-form-urlencoded
でOK(指定不要)。 -
ファイル送信するなら、
method="post"
とenctype="multipart/form-data"
は絶対セットで指定! これ最重要! -
text/plain
は、まあ、忘れてもいいかも…。
encType
を正しく使い分けるだけで、フォーム関連、特にファイルアップロード周りのトラブルはぐっと減るはずです。ぜひ開発ツールのネットワークタブも活用して、実際にどんなデータが送られているか確認してみてください。
Discussion