レッスン 5
フォームデータにおけるプラス記号
クエリ文字列で `+` がスペースを意味することがある理由と `%20` vs `+`。
URL 内のスペースは歴史的に問題だったため、デフォルト HTML <form method="GET"> が使う application/x-www-form-urlencoded は、シリアライズ body またはクエリ部分文字列でスペースを + としてエンコードします。
<form>
<input name="msg" value="hello world">
</form>
<!-- 送信 URL に ?msg=hello+world が含まれることがある -->
これはすべてのツールパスで汎用 URI percent エンコードと同じルールではありません: 多くの URI プロセッサーは、form-urlencoded 意味論を明示しない限り + をリテラル plus として扱います。
?msg=a+b // パーサーモード次第で "a b" または "a+b"
?q=city%20hall // ASCII スペースの明確な URI percent エンコード (%20)
JavaScript ヘルパー
URLSearchParams
const p = new URLSearchParams("a=b+c");
console.log(p.get("a")); // フォームモードでは '+' をスペースと解釈しがち
オブジェクトから作成すると stringify 時にフォームルールを保持:
new URLSearchParams({ tag: "a+b" }).toString(); // '+' 向けに a%2Bb や tag=a%2Bb パターン(内部実装次第)
console.log(String(new URLSearchParams({ expr: "1+2" })));
相互運用可能なリテラルが必要なら、plus を plus のまま残す必要がある場合は明示的に percent エンコード(%2B)。
手動デコードのミス
decodeURIComponent だけでは percent シーケンスのみ想定 — '+' は変換しない:
decodeURIComponent('a+b'); // "a+b" のまま
decodeURIComponent('a+b'.replace(/\+/g, " ")); // 手動フォーム型修正 — 層が正しいときのみ
サーバーフレームワーク
人気スタックはトグルを公開(application/x-www-form-urlencoded パーサー vs 生クエリパーサー)。ミドルウェア順序が重要:
- URI コンポーネント意味論でクエリをパース。
+→ スペースルール付き HTML フォーム意味論でパース。
誤設定は、環境間で '+' の意味が変わりハッシュトークンが壊れるなどのバグを生みます。
何をいつエンコードするか
| 必要 | 推奨 |
|---|---|
URL を跨ぐフォームフィールド値のリテラル '+' | 値層で %2B をエンコード |
JSON 輸送の人間可読 '+' | クエリより JSON body を優先 |
| デバッグログ | パーサーが書き換える前の生バイト(req.url)を捕捉 |
+ を理解すると、二重デコード、パーサー不一致、本当に %2B が必要なユーザー入力、のバグ分類に役立ちます。レッスン 4 の部分デコード後の脆い split('&') 警告と組み合わせてください。