検索リンクを作ろうと日本語のキーワードを URL に付けたら、クリックすると別のページへ飛ぶ。あるいはパラメータの値に & が入った途端、その後ろがまるごと切れてしまう。原因はたいてい、エンコード関数の選び間違いです。URL エンコードの肝は、2つの関数の違いにあります。
component か full か、まず範囲を決める
JavaScript には URL エンコード関数が2つあります。違いは、予約文字に手を付けるかどうかです。
encodeURIComponent(component モード)は / ? # & = などの予約文字までパーセントエンコードします。値ひとつ、パス断片ひとつを扱うときに使います。encodeURI(full モード)はそれらの区切りを保持します。すでに形の整った URL 全体をエンコードするときに使います。MDN も2つを用途で区別しています。選び間違えた瞬間にバグが始まります。
クエリ値に予約文字があれば component
最もよく起きる場面です。パラメータの値の中に & や = が入るときです。
値として a=1&b=2 を入れるとしましょう。PiPi Worlds の URL エンコードツールで component でエンコードすると a%3D1%26b%3D2 が出ます。= と & がそれぞれ %3D・%26 に変わり、1つの値として安全に収まります。一方 full でエンコードすると a=1&b=2 のままです。これを ?x=a=1&b=2 のように付けると、サーバーは &b=2 を別のパラメータとして読み、データが壊れます。値には component が答えです。
URL 全体をエンコードするなら full
逆の状況もあります。すでに完成した URL 全体をエンコードしたいときです。
https://pipi-worlds.com/道?q=こんにちは を full でエンコードすると https://pipi-worlds.com/%E9%81%93?q=%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF になります。://・/・?・= はそのまま残し、日本語だけをパーセントに変えます。ここで component を使うと https%3A%2F%2Fpipi-worlds.com... のようにスキームの区切りまで全部エンコードされ、アドレス自体が壊れます。範囲が「URL 全体」なら full です。
’+’ が空白になる罠
デコードで人を惑わせるのが + です。同じ a+b が、出所によって違うふうに解釈されます。
HTML フォーム送信の規格 application/x-www-form-urlencoded では空白を + で表します。しかし通常の URL では + はただの「+」です。そのためツールで a+b をデコードすると、「+ を空白に」がオフなら a+b、オンなら a b になります。受け取った文字列がフォーム由来か URL 由来かで、トグルを合わせる必要があります。
そのパーセントの塊、正体が分からないとき
最後は受け取る側の話です。ログやリダイレクトの URL で %E3%81%82... のような塊に出会ったが、これがフォームデータなのか URL 断片なのか、+ をどう見るべきか、ひと目では分かりません。
PiPi Worlds の URL エンコードツールは、component・full と「+ 空白」のトグルを切り替えながら結果を見比べられ、変換はすべてブラウザ内で実行されるため入力はサーバーへ送られません。途中で切れた % のような壊れた列は、文字化けではなくエラーとして知らせます。URL の中の値が base64 なら Base64 ツール、JSON の断片なら JSON フォーマッターへそのまま続けて確認できます。