URL エンコード

文字列を貼り付けると、URL で使えるようにパーセントエンコードされて返ってきます。効いてくる唯一の判断は、推測ではなく選択として提示します。アドレスの中に入る値をエンコードしているのか、それともスラッシュや疑問符が構造であり生き残らなければならないアドレス全体なのか。この 2 つを取り違えると、正しく見えて別の場所へ行く URL ができます。

値は ? & = / # をエスケープします。アドレス全体はそれらを保ちます。そこでは構造だからです。

結果

入力すると、ここに答えが出ます。

  • 処理される場所

    ファイルがないので、何もアップロードされません。計算はこのページの中で行われます。

  • 順番待ちもアカウントもなし

    お使いの機械の速さで答え、あなたが誰かを尋ねることはありません。

  • 何度でも

    回数は数えず、上限もありません。もう一度答えることに費用はかからないからです。

仕組み

  1. テキストを欄に貼り付けてください。
  2. それが何かを指定します。URL の中の値か、アドレス全体か。? と & をエスケープするかどうかが決まります。
  3. 結果をコピーします。何も送信されていません。

このツールが尋ねる唯一の問い

URL は部分でできていて、それらを区切る文字——`/`、`?`、`&`、`=`、`#`——は、その役割を果たしているときは構造であり、そうでないときはデータです。アドレス全体のエンコードはそれらに触れてはならず、触れればアドレスでなくなります。単独の値のエンコードはそれらを逃がさなければならず、さもなければ値がそこで終わって別の何かが始まります。

これは `encodeURI` と `encodeURIComponent` の違いそのもので、ウェブに存在する壊れたリダイレクトパラメーターの大半がここから出ています。`?next=https://example.com/a?b=c` の 2 つめの疑問符がエスケープされておらず、その後ろがすべて外側の URL のものになる。リンクは、遷移先にクエリ文字列のないテスト環境では動き、ある本番では壊れます。

パーセント列が運ぶのはバイトで、文字ではありません

パーセント列は `%` に 16 進 2 桁が続いたもので、1 バイトを指します。ASCII の外の文字は複数必要です。「あ」は `%E3%81%82` の 3 列で、漢字も 3 列、絵文字は 4 列です。

古い `escape()` 関数はこれをまったく別に扱い、U+00FF を超える文字に `%u3042` という独自の形を出します。標準ではなく、これを受け取ったサーバーはパーセントデコードでは戻せません。その出力はいまも古いコードと一部の古い連携に残っています。ここでは最初から最後まで UTF-8 です。

署名を壊す 5 つの文字

`encodeURIComponent` は感嘆符、アポストロフィー、2 種類の丸かっこ、アスタリスクをエスケープしません。RFC 3986 はそれらを予約文字として挙げているので、厳密に準拠するエンコーダーはエスケープします。両者は、普通の文章に絶えず現れる 5 つの文字で食い違います。

気づくのは署名が絡んだときだけです。OAuth 1.0 と AWS Signature Version 4 はエンコード後の文字列に対してハッシュを計算するので、エスケープされていないアポストロフィーが 1 つあるだけでハッシュが変わり、リクエストが拒否されます。しかも資格情報に関するエラーとして返るので、まったく見当違いの場所を探すことになります。ここの厳密モードは 5 つとも逃がします。

空白は %20 か、プラス記号か

両方が現れ、しかも同じ規則ではありません。`%20` はパーセントエンコードで、URL のどの部分でも正しい形です。プラス記号は `application/x-www-form-urlencoded`——HTML のフォームが送信する形式——から来ていて、そこでは空白が `+` と書かれます。現在の仕様より古い慣習が、フォームが生き残っているために生き残っています。

パスの中の `+` は本物のプラスです。クエリ文字列の中では、フォームの符号化がそう定めているため、ほとんどのサーバーが空白として読みます。つまりクエリの値の中の本物のプラスは `%2B` と書かなければ消えます。このエンコーダーは `%20` を出します。どちらの場所でも曖昧になりません。

二重エンコードと、その見分け方

すでにエンコードされた文字列をエンコードすると `%` 自体が逃がされ、`%20` は `%2520` になります。関係するどの部品にとってもこれは誤りではありません。文字列「%20」の完全に妥当なエンコードです。だから二重エンコードは、利用者が見出しに `こんにちは%20世界` を見る地点まで生き延びます。

手がかりは、`%` があるべき場所の `%25` です。見つけたら、鎖のどこかがエンコード済みの値をもう一度エンコードしています。たいていはフレームワークが自動でやり、テンプレートがもう一度やっています。直し方は片方を取り除くことで、末端で 2 回デコードすることではありません。

決してエスケープしてはいけないもの

英数字と `-`、`_`、`.`、`~` の 4 文字は RFC 3986 で「unreserved」と呼ばれ、決してエスケープすべきではありません。ピリオドの代わりに `%2E` を出すエンコーダーは厳密なのではなく、間違っています。一部のシステムはそれを元に戻して正規化し、別のシステムはしないので、同じであるべき 2 つの URL が同じでなくなります。

実務上は、テキストがほとんど英数字なのにパーセント列だらけになっている文字列は、過剰にエンコードする道具から来ていることが多いです。誰かがそれに対して署名やキャッシュキーを計算するまでは無害で、そこから先は 2 つのシステムが噛み合わない理由になります。

フラグメントは決して送られません

`#` より後ろのものはすべてブラウザーに留まります。どのリクエストにも現れず、どのサーバーにも届かず、どのアクセスログにも載りません。プライバシー機能ではなく HTTP の性質で、両方向に切れます。

便利なのは、そこに置いた値がサーバーへ届かないからです。歴史的に OAuth のトークンがそこを旅した理由でもあります。厄介なのは、それでもブラウザーの履歴に残り、一部のスクリプトのリファラー連鎖に残り、共有されたリンクに残るからです。「サーバーへ届かない」は「非公開である」ではありません。

ホスト名はパーセントエンコードされません

日本語のドメイン名はエスケープされません。Punycode に変換されます。`日本.example` は `xn--wgv71a.example` になります。これが DNS に実在する形です。名前解決の仕組みは ASCII しか知りません。

ホストを値のように扱うエンコーダーは、どの DNS も解決できないアドレスを作ります。だからここのアドレス全体モードはホストに触れません。そして日本語ドメインを含む URL を組み立てているなら、ホストの変換はこの操作の一部ではなく、別の手順です。

個人情報保護法から見たときの位置

エンコードされたものはたいてい URL に入り、URL はサーバーのログ、ブラウザーの履歴、次のクリックのリファラーヘッダーに残ります。値にメールアドレスや識別子や個人的な検索語が入っていれば、使われた瞬間にすでに複数の場所にあります。

このページが解決するのは、エンコードがあなたの端末で行われ、その値が当方へ提供されないという部分です。解決できないのはもう一方で、それはここで言うに値します。個人データが意図せず記録される最も多い場所は、URL のパラメーターです。

URL エンコード:よくある質問

3 つのモードのどれが必要ですか。

テキストがアドレスの中に入る値なら 1 つめです。? & = / # を逃がします。アドレス全体なら 2 つめで、そこでは構造なので保ちます。3 つめが要るのは署名が絡むときだけです。

「あ」が 3 つのパーセント列になるのはなぜですか。

パーセントエンコードがバイトを運び、UTF-8 が「あ」を 3 バイトで書くからです。%E3%81%82 になります。古い escape() は %u3042 という独自の形を出しますが、これは標準ではなく、受け取った側は普通には戻せません。

URL に %2520 が見えます。何を意味しますか。

二重にエンコードされたということです。%20 がもう一度エンコーダーを通り、その % が逃がされました。直し方は 2 つの段のうち片方を取り除くことで、末端で 2 回デコードすることではありません。

空白は %20 とプラス記号のどちらですか。

%20 は URL のどの部分でも正しい形です。+ が空白を意味するのはクエリ文字列だけで、フォームの符号化を受け継いだものです。パスでは本物のプラスです。ここでは曖昧にならない %20 を出します。

テキストは端末から出ますか。

いいえ。このページの中でエンコードされます。ただし、その URL がいったん使われれば、値はサーバーのログ、履歴、リファラーヘッダーに残ることは念頭に置いてください。

他のツール