application/x-www-form-urlencoded エンコード

HTMLフォームデータがapplication/x-www-form-urlencodedでエンコードされる仕組みを解説。標準URLエンコードとの違い、スペースの+表現を学びましょう。

Character

form data

Encoded

+

詳細な説明

application/x-www-form-urlencodedコンテンツタイプは、HTMLフォーム送信のデフォルトエンコードです。URL percent-encodingと密接に関連していますが、最も顕著な違いとして、スペースが%20ではなく+にエンコードされます。

フォームエンコードの仕組み:

  1. 各フォームフィールドの名前と値をエンコードする
  2. スペースを+に置換する
  3. 英数字以外の文字(-_.*を除く)をpercent-encodingする
  4. 名前と値のペアを=で結合する
  5. ペアを&で区切る

例:

フォームフィールド:
  name: "John Doe"
  message: "Hello & goodbye!"

エンコードされたボディ:
  name=John+Doe&message=Hello+%26+goodbye%21

JavaScriptでの動作:

// URLSearchParams はフォームエンコードされた出力を生成する
const formData = new URLSearchParams({
  name: "John Doe",
  message: "Hello & goodbye!"
});
formData.toString();
// "name=John+Doe&message=Hello+%26+goodbye%21"

// フォームエンコードで fetch する
fetch("/api/submit", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: formData.toString()
});

// 標準URLエンコードとの比較
encodeURIComponent("John Doe"); // "John%20Doe" (フォームエンコードではない)

RFC 3986 percent-encodingとの主な違い:

特徴 フォームエンコード RFC 3986
スペース + %20
アスタリスク * エンコードしない エンコードしない
チルダ ~ %7Eとしてエンコード(レガシー) エンコードしない

フォームエンコードが使用される場面:

  • HTML <form method="GET">送信(データはURLクエリ文字列に入る)
  • デフォルトenctypeでのHTML <form method="POST">送信
  • Content-Type: application/x-www-form-urlencodedを使用するAJAXリクエスト
  • OAuth 1.0署名ベース文字列

フォームエンコードを使用すべきでない場面:

  • ファイルアップロード(代わりにmultipart/form-dataを使用)
  • JSON APIリクエスト(application/jsonを使用)
  • URLパスセグメント(標準percent-encodingを使用)

落とし穴: サーバーがクエリパラメータを受信する際、+をスペースとしてデコードするかリテラルのプラス記号としてデコードするかを判断する必要があります。HTMLフォームGET送信からのクエリ文字列はフォームエンコード(+ = スペース)を使用しますが、手動で構築されたクエリ文字列はRFC 3986エンコード(+ = リテラルプラス)を使用する場合があります。ほとんどのサーバーフレームワークはクエリ文字列にフォームエンコードを想定するため、値のリテラルの+%2Bとして送信すべきです。

ユースケース

POSTリクエストでのHTMLフォームデータの送信、OAuth署名ベース文字列の構築、フォームエンコードペイロードを期待するAPIへのデータ送信。

Try It — URL Encoder

フルツールを開く