URL エンコード/デコード:全体・パラメーター値・%20 の違い
1つのパラメーター値なら、その値を encodeURIComponent の規則でエンコードし、リンクの構造を保ちたいなら「パラメーター値のみ」を使って ? と & で分割し、値だけを処理します。デコードは %XX の並びを元のテキストに戻します。
必要な場面
URL に日本語、空白、区切り文字としても使われる & などが含まれる場合です。そのまま貼り付けるとリンクが途中で切れたり、意図しない形で解析されたりするため、先にエンコードが必要です。値にすでに %26 が含まれている場合、「パラメーター値のみ」は一度デコードしてから再エンコードするので、%2526 のように二重化しません。
ログ、アクセス解析、メールから %E4%B8%AD%E6%96%87 のような文字列を取り出し、読める形に戻したい場合です。絵文字のような4バイトの UTF-8 シーケンスも正しく復元できます。
外部サービスのコールバックで、return_url を別のパラメーターの中に入れるためにエンコードする必要がある場合です。全体をエンコードするのと値だけをエンコードするのでは結果が変わり、選び方を間違えると層が1つ増えたり抜けたりします。
- 日本語や空白を含むパラメーター値
- ログやメールの %E4%B8%AD%E6%96%87 を元に戻す
- コールバック URL を別のパラメーターに入れ子にする
- 署名前の文字列を正規化する
失敗しないための手順
2つの関数の違いを押さえてください。encodeURIComponent は / ? & = などの区切り文字もエスケープし、1つのパラメーター値に向いています。encodeURI はそれらを残し、URL 全体に向いています。このツールの「全体」は前者なので、:// も %3A%2F%2F になります。URL の構造を残したい場合は使わないでください。
「パラメーター値のみ」は ? と & で分割し、各値を処理します。既存のパーセントエンコードを一度デコードしてから再エンコードするため、%2526 のような重なりを防げます。ただし # フラグメントと ; 区切りは扱わないので、必要な場合は自分で分割してください。
空白は %20 で、+ ではありません。encodeURIComponent は RFC 3986 に従い、空白を常に %20 にします。空白を + と書くのは、HTML フォームの application/x-www-form-urlencoded の規則です。クエリ文字列では多くのフレームワークが両方を受け付けますが、署名アルゴリズム、OAuth、古いゲートウェイの中には + を文字としてのプラスとして扱うものがあります。+ が必要なときは、文字を手で置換するのではなく URLSearchParams で生成してください。正しい %2B まで壊してしまいます。
「不正なパーセントエスケープが含まれています」というエラーは、孤立した %、%ZZ、%E4 のような途中で切れた並びが原因です。よくあるのは、リンクが二重にエンコードされている、チャットアプリで文字数制限により切り捨てられた、元のテキストに 100% のような表記があった、の3つです。文字としてのパーセント記号は %25 と書きます。不正な並びがあると全体が失敗し、途中までデコードした結果は返りません。
1回デコードしても文字化けする場合、多くの場合は二重エンコードです。コールバック URL が別のリダイレクトパラメーターの中に入れられているときに起こりがちです。デコードは1回につき1層だけ剥がします。%25E4%25B8%25AD は %E4%B8%AD になり、次に「中」になります。続けて押しても構いませんが、今どの層を剥がしているのかを把握してください。根本的な対処は、発生元で1回だけエンコードすることです。
- 1つの値は encodeURIComponent、URL 全体は encodeURI
- 「値のみ」は %2526 の重なりを防ぐ
- 空白は %20。+ はフォームの規則
- 不正な % は全体が失敗する。パーセント記号を確認する
代替手段と限界
コードでは URL と URLSearchParams を使ってください。仕様に沿ってエンコード、+ の扱い、順序を処理します。new URL(...).searchParams.set(...) は値を自動でエンコードします。
URL 全体の構造を保ちたい場合は encodeURI を使います。フォームの本文や署名対象の文字列を作る場合は、URLSearchParams.toString() を使います。フォームの規則で + を出力します。
このツールの限界は次のとおりです。区切りは ? と & だけなので # フラグメントと ; は扱いません。空白は + ではなく %20 を出力します。不正なパーセント並びはエラーになり、部分的なデコードは行いません。大文字小文字、既定ポート、.. を含むパスの正規化も行いません。
- コードでは URL と URLSearchParams
- URL 全体 → encodeURI
- フォーム本文や署名 → URLSearchParams
- 正規化 → 専用ライブラリ
よくある質問
URL エンコードで空白が + ではなく %20 になるのはなぜですか?
encodeURIComponent が RFC 3986 に従い、空白を常に %20 にするためです。空白を + と書くのは、HTML フォームの application/x-www-form-urlencoded の規則です。クエリ文字列の多くはどちらも受け付けますが、署名、OAuth、古いゲートウェイでは + を文字としてのプラスとして扱い、値が変わることがあります。+ が必要なときは、文字を手で置換するのではなく URLSearchParams で生成してください。既存の %2B まで壊してしまいます。
encodeURI と encodeURIComponent の違いは何ですか?
encodeURIComponent は URL の構造を作る予約文字(/ ? & = : # など)もエスケープするため、1つの値に向いています。encodeURI はそれらを残し、URL に直接置けない文字だけをエンコードするため、URL 全体に向いています。このツールの「全体」は encodeURIComponent と同じ動きで、:// も %3A%2F%2F になります。
1回デコードしても文字化けします。2回必要ですか?
多くの場合は二重エンコードです。デコードは1回につき1層だけ剥がします。%25E4%25B8%25AD は %E4%B8%AD になり、もう一度押すと「中」になります。リダイレクトのパラメーターに入れ子になっているのがよくある原因です。2回押しても結果は得られますが、発生元で1回だけエンコードするほうが本質的な対処です。二重エンコードは + や & の意味も予測しにくくします。
関連ツール:URL Encode/Decode