URLエスケープエンコーディングの特殊文字に基づいて

URLエスケープエンコーディングの特殊文字に基づいて

URL 内の特殊文字

文字 - URLエンコードされた値

スペース - %20
" - %22
# - %23
% - %25
& - %26
(-%28
) - %29
+ - %2B
、-%2C
/ - %2F
: - %3A
; - %3B
<-%3C
= - %3D
> - %3E
? - %3F
@ - %40
\ - %5C
|-%7C

URL 特殊文字エスケープ、URL 内の一部の文字には特別な意味があり、基本的なエンコード ルールは次のとおりです。

1. スペースをプラス記号(+)に置き換える

2. スラッシュ(/)はディレクトリとサブディレクトリを区切ります

3. 疑問符(?)はURLとクエリを区切る

4. パーセント記号(%)は特殊文字を指定します

5. # ブックマークを指定します

6. & はパラメータを区切ります

URL 内で使用する必要がある場合は、これらの特殊文字を対応する 16 進数値に置き換える必要があります。

+ %2B
/ %2F
? %3F
% %25
# %23
& %26

この記事では、主に URI エンコードとデコードに関連する問題を紹介し、URL エンコードでエンコードする必要がある文字と、エンコードする必要がある理由について詳しく説明します。また、JavaScript のエンコードとデコードに関連するいくつかの関数ペア (escape/unescape、encodeURI/decodeURI、encodeURIComponent/decodeURIComponent) を比較して分析します。

前提条件

foo://example.com:8042/over/there?name=フェレット#鼻
\_/ \______________/ \________/__________/ \__/
| | | | |
スキーム権限パスクエリフラグメント

URI は Uniform Resource Identifier の略です。通常、URL と呼ばれるものは URI の一種です。一般的な URL の形式は上記に示されています。以下で説明する URL エンコーディングは、実際には URI エンコーディングを指します。

URL エンコードが必要なのはなぜですか?

通常、何かをエンコードする必要がある場合、それは送信には適していません。理由はさまざまですが、サイズが大きすぎる、プライベート データが含まれている、URL の場合は一部の文字があいまいになる可能性があるためエンコードが必要である、などです。

たとえば、Url パラメータ文字列では、パラメータを渡すためにキー = 値のペア形式が使用され、キーと値のペアは & 記号で区切られます (例: /s?q=abc& ie=utf-8)。値の文字列に = または & が含まれている場合、URL を受信するサーバーで解析エラーが必然的に発生するため、あいまいな & および = 記号はエスケープ、つまりエンコードする必要があります。

たとえば、Url のエンコード形式では Unicode ではなく ASCII コードが使用されるため、中国語などの非 ASCII 文字を Url に含めることはできません。そうでない場合、クライアント ブラウザーとサーバー ブラウザーが異なる文字セットをサポートしていると、中国語で問題が発生する可能性があります。

URL エンコーディングの原則は、安全な文字 (特別な目的や特別な意味を持たない印刷可能な文字) を使用して安全でない文字を表すことです。

どの文字をエンコードする必要がありますか?

RFC3986 ドキュメントでは、URL には英語の文字 (a-zA-Z)、数字 (0-9)、-_.~4 の特殊文字、およびすべての予約文字のみを含めることができると規定されています。

RFC3986 ドキュメントでは、URL のエンコードとデコードに関する詳細な推奨事項が提供されており、URL のセマンティクスを変更しないようにエンコードする必要がある文字が示され、これらの文字をエンコードする必要がある理由が説明されています。

US-ASCII文字セットには対応する印刷可能な文字はありません

URL では印刷可能な文字のみが許可されます。 US-ASCII コードのバイト 10 ~ 7F はすべて制御文字を表し、これらの文字は URL に直接表示できません。同時に、80-FF バイト (ISO-8859-1) は US-ACII で定義されたバイト範囲を超えているため、URL に配置することはできません。

予約文字

URL は、プロトコル、ホスト、パスなどの複数のコンポーネントに分割できます。いくつかの文字 (:/?#[]@) は、異なるコンポーネントを区切るために使用されます。たとえば、コロンはプロトコルとホストを区切るために使用され、/ はホストとパスを区切るために使用され、? はパスとクエリ パラメータを区切るために使用されます。また、各コンポーネントを区切るために使用される文字 (!$&'()*+,;=) もあります。たとえば、= はクエリ パラメータ内のキーと値のペアを表すために使用され、& 記号はクエリ内の複数のキーと値のペアを区切るために使用されます。コンポーネント内の通常のデータにこれらの特殊文字が含まれている場合は、エンコードする必要があります。

RFC3986 では、次の文字を予約文字として指定しています。

* ' ; : @ = + $ / ? # [ ]

安全でない文字

また、URL に直接配置すると、パーサーであいまいさが生じる可能性がある文字もいくつかあります。これらの文字は、いくつかの理由から安全ではないと見なされます。

空間URL が送信されるとき、ユーザーが URL をフォーマットするとき、またはテキスト処理プログラムが URL を処理するときに、重要でないスペースが挿入されたり、重要なスペースが削除されたりする可能性があります。
引用符と<>通常のテキストでは、URL を区切るために引用符と山括弧が使用されます。
#通常、ブックマークやアンカーを示すために使用されます
%パーセント記号自体は安全でない文字をエンコードする際に特殊文字として使用されるので、それ自体をエンコードする必要がある。
{}|\^[]`~一部のゲートウェイや伝送エージェントはこれらの文字を改ざんすることがある

URL 内の有効な文字については、エンコードと非エンコードは同等ですが、上記の文字については、エンコードしないと URL のセマンティクスに違いが生じる可能性があることに注意してください。したがって、URL の場合、エンコードされていない URL には、一般的な英語の文字と数字、特殊文字 $-_.+!*'()、および予約文字のみが表示されます。その他の文字は、URL に表示される前にエンコードする必要があります。

ただし、歴史的な理由により、非標準のエンコーディング実装がまだいくつか存在します。たとえば、~記号の場合、RFC3986文書ではチルダ記号~はURLエンコードする必要がないと規定されていますが、古いゲートウェイや転送エージェントではURLエンコードする必要がないものが多くあります。

URL で不正な文字をエンコードする方法

URL エンコーディングは、パーセント記号と 2 つの文字 (0123456789ABCDEF) を使用して 16 進形式でバイトを表すという非常に単純なエンコーディング方法であるため、パーセント エンコーディング (URL エンコーディング、パーセント エンコーディングとも呼ばれます) とも呼ばれます。 URL エンコードに使用されるデフォルトの文字セットは US-ASCII です。たとえば、US-ASCII コードで a に対応するバイトは 0x61 なので、Url エンコード後の結果は %61 になります。アドレス バーに http://g.cn/search?q=%61%62%63 と入力すると、実際には Google で abc を検索するのと同じになります。たとえば、ASCII 文字セットで @ 記号に対応するバイトは 0x40 ですが、URL エンコード後は %40 になります。

URL エンコードでよく使用される文字のリスト:

予約文字の URL エンコード
* ' ; : @
%21 %2A %22 %27 %28 %29 %3B %3A %40 %26
= + $ / ? % # [ ]
%3D %2B %24 %2C %2F %3F %25 %23 %50億%5D

非 ASCII 文字の場合、ASCII 文字セットのスーパーセットを使用して対応するバイトをエンコードし、各バイトに対してパーセント エンコードを実行する必要があります。 Unicode 文字の場合、RFC ドキュメントでは、UTF-8 を使用してエンコードし、対応するバイトを取得し、各バイトに対してパーセント エンコードを実行することを推奨しています。たとえば、UTF-8 文字セットを使用した「中国語」のバイトは 0xE4 0xB8 0xAD 0xE6 0x96 0x87 であり、URL エンコード後は「%E4%B8%AD%E6%96%87」になります。

バイトが ASCII 文字セット内の予約されていない文字に対応する場合、そのバイトをパーセント記号で表す必要はありません。 たとえば、「Url エンコード」は UTF-8 でエンコードされ、バイトは 0x55 0x72 0x6C 0xE7 0xBC 0x96 0xE7 0xA0 0x81 です。最初の 3 バイトは ASCII の非予約文字「Url」に対応するため、これらの 3 バイトは非予約文字「Url」で表すことができます。最終的な URL エンコードは、「Url%E7%BC%96%E7%A0%81」に簡略化できます。もちろん、「%55%72%6C%E7%BC%96%E7%A0%81」を使用しても問題ありません。

歴史的な理由により、一部の URL エンコード実装はこの原則に完全に従っていません。これについては後述します。

Javascript における escape、encodeURI、encodeURIComponent の違い

Javascript には、URL をエンコードして有効な URL を取得するための 3 組の関数 (escape/unescape、encodeURI/decodeURI、encodeURIComponent/decodeURIComponent) が用意されています。デコードとエンコードのプロセスは可逆的なので、ここではエンコードのプロセスについてのみ説明します。

これら 3 つのエンコード関数 (escape、encodeURI、encodeURIComponent) はすべて、安全でない不正な URL 文字を有効な URL 文字表現に変換するために使用されます。これらには次の違いがあります。

セキュリティ文字は異なります

次の表は、これら 3 つの関数で安全な文字を示しています (つまり、関数はこれらの文字をエンコードしません)。

安全な文字
逃げる(69) */@+-._0-9a-zA-Z
エンコードURI (82) !#$&'()*+,/:;=?@-._~0-9a-zA-Z
エンコードURIコンポーネント (71) !'()*-._~0-9a-zA-Z

異なる互換性

escape 関数は Javascript 1.0 から存在していましたが、他の 2 つの関数は Javascript 1.5 で導入されました。ただし、Javascript 1.5 はすでに非常に普及しているため、encodeURI と encodeURIComponent を使用する場合、実際には互換性の問題はありません。

Unicode文字のさまざまなエンコード方法

これら 3 つの関数は、パーセント記号 + 2 つの 16 進文字で表される ASCII 文字の同じエンコード方法を使用します。ただし、Unicode 文字の場合、エスケープ エンコーディングは %uxxxx です。ここで、xxxx は Unicode 文字を表すために使用される 4 桁の 16 進文字です。このメソッドは W3C によって非推奨になりました。ただし、エスケープ エンコード構文は ECMA-262 標準に引き続き保持されます。 encodeURI と encodeURIComponent は、UTF-8 を使用して非 ASCII 文字をエンコードし、パーセントエンコードします。これは RFC で推奨されています。したがって、エンコードには可能な限りエスケープではなく、これら 2 つの関数を使用することをお勧めします。

さまざまな場面に適用可能

encodeURI は完全な URI をエンコードするために使用され、encodeURIComponent は URI のコンポーネントをエンコードするために使用されます。

上記の安全な文字範囲表から、encodeURIComponent によってエンコードされる文字範囲は encodeURI よりも広いことがわかります。上で述べたように、予約文字は通常、URI コンポーネント (URI は複数のコンポーネントに分割できます。前提条件の知識のセクションを参照) またはサブコンポーネント (URI 内のクエリ パラメータの区切り文字など) を区切るために使用されます。たとえば、: 文字はスキームとホストを区切るために使用され、? 文字はホストとパスを区切るために使用されます。 encodeURI によって操作されるオブジェクトは完全な URI であるため、これらの文字は URI で特別な用途を持ちます。したがって、これらの予約文字は encodeURI によってエンコードされません。エンコードすると意味が変わります。

コンポーネントには独自のデータ表現形式がありますが、これらのデータにはコンポーネントを区切る予約文字を含めることはできません。そうしないと、URI 全体のコンポーネントの区切りが混乱します。したがって、単一のコンポーネントに encodeURIComponent を使用する場合は、より多くの文字をエンコードする必要があります。

フォーム送信

HTML フォームが送信されると、各フォーム フィールドは送信される前に URL エンコードされます。歴史的な理由により、フォームで使用される URL エンコードの実装は最新の標準に準拠していません。たとえば、スペースに使用されるエンコードは %20 ではなく、+ 記号です。フォームが Post メソッドを使用して送信された場合、HTTP ヘッダーに application/x-www-form-urlencoded という値を持つ Content-Type ヘッダーが表示されます。ほとんどのアプリケーションは、この URL エンコードの非標準実装を処理できますが、クライアント側の JavaScript には + 記号をスペースにデコードできる関数がないため、独自の変換関数を記述することしかできません。また、非 ASCII 文字の場合、使用されるコード化文字セットは、現在のドキュメントで使用されている文字セットによって異なります。例えば、HTMLヘッダーに

<meta http-equiv="コンテンツタイプ" コンテンツ="text/html; charset=gb2312" />

この方法では、ブラウザは gb2312 を使用してドキュメントをレンダリングします (このメタ タグが HTML ドキュメントに設定されていない場合、ブラウザは現在のユーザーの設定に基づいて文字セットを自動的に選択します。また、ユーザーは現在の Web サイトで指定した文字セットを使用するように強制することもできます)。フォームを送信するときに、URL エンコードに使用される文字セットは gb2312 です。

ドキュメントの文字セットは encodeURI に影響しますか?

以前、Aptana を使用したときに非常に混乱する問題に遭遇しました (aptana について具体的に言及した理由は後述します)。encodeURI を使用したところ、エンコードされた結果が予想と大きく異なることがわかりました。サンプルコードは次のとおりです:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">     
<ヘッド>         
<meta http-equiv="コンテンツタイプ" コンテンツ="text/html; charset=gb2312" />     
</head>     
<本文>         
<script type="text/javascript">             
document.write(encodeURI("中国語"));         
</スクリプト>     
</本文> 
</html> 

実行結果の出力は %E6%B6%93%EE%85%9F%E6%9E%83 です。明らかに、これは URL エンコードに UTF-8 文字セットを使用した結果ではありません (Google で「中国語」を検索すると、URL に %E4%B8%AD%E6%96%87 が表示されます)。

当時は encodeURI もページ エンコーディングに関連しているのではないかと非常に懐疑的でしたが、通常の状況では、URL エンコーディングに gb2312 を使用すると、この結果は得られないことがわかりました。その後、ページ ファイルの保存に使用される文字セットと Meta タグで指定された文字セットの不一致が問題の原因であることがようやくわかりました。 Aptana のエディターはデフォルトで UTF-8 文字セットを使用します。つまり、このファイルが実際に保存されるときには、UTF-8 文字セットが使用されます。ただし、Meta タグに gb2312 が指定されているため、ブラウザーは gb2312 に従ってドキュメントを解析します。当然、「中文」文字列にエラーが発生します。これは、「中文」文字列を UTF-8 でエンコードした後に取得されるバイトが 0xE4 0xB8 0xAD 0xE6 0x96 0x87 であり、この 6 バイトがブラウザーによって gb2312 でデコードされ、さらに 3 つの中国語文字「涓枃」が得られるためです (GBK では 1 つの中国語文字が 2 バイトを占めます)。この 3 つの中国語文字が encodeURI 関数に渡された後の結果は %E6%B6%93%EE%85%9F%E6%9E%83 です。したがって、encodeURI は引き続き UTF-8 を使用し、ページ文字セットの影響を受けません。

URLエンコードに関連するその他の問題

中国語の文字を含む URL の処理に関しては、ブラウザによって応答が異なります。たとえば、IE の場合、詳細設定の「URL を常に UTF-8 で送信する」をチェックすると、URL のパス部分の中国語文字は UTF-8 でエンコードされてサーバーに送信され、クエリ パラメータの中国語部分はシステムのデフォルト文字セットでエンコードされます。最大限の相互運用性を確保するには、ブラウザのデフォルトの実装に依存せずに、URL に配置されるすべてのコンポーネントで URL エンコードの文字セットを明示的に指定することをお勧めします。

さらに、多くの HTTP 監視ツールやブラウザのアドレス バーは、URL を表示するときに URL を自動的にデコードします (UTF-8 文字セットを使用)。このため、Firefox で Google にアクセスして中国語を検索すると、アドレス バーに表示される URL に中国語が含まれます。しかし実際には、サーバーに送信された元の URL はまだエンコードされています。これは、Javascript を使用してアドレス バーの location.href にアクセスすると確認できます。 URL のエンコードとデコードを学習する際には、こうした錯覚に惑わされないでください。

上記は私の個人的な経験です。参考になれば幸いです。また、123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • URLパラメータ内の+、スペース、=、%、&、#などの特殊記号の問題の解決策
  • JavaScript の URL 投稿の特殊文字エスケープ + & # を解決する 2 つの方法
  • URLパラメータ内のプラス記号はスペース(URL特殊文字)に変換されます

<<:  VMware インストール後に仮想ネットワーク カードが表示されない問題について

>>:  なぜ IE6 が最も多くの人に使用されているのでしょうか?

推薦する

WeChatミニプログラムページ間の価値転送を実装する方法の例

ミニプログラムページ間で値を渡すみなさんこんばんは。こんばんはと言うのは、これを夜に書いたからです。...

Jenkins + Docker + ASP.NET Core の自動デプロイメントの問題について (落とし穴を避ける)

このブログを書くつもりはなかったのですが、実際の操作中に、ネットワークの問題に圧倒されたこと (ネッ...

vue+drf+サードパーティのスライディング検証コードアクセスの実装

目次1. 背景2. 検証プロセス3. 検証を作成する4. フロントエンドコード4.1 コアjsファイ...

テーブルの追加と削除の操作を実装する js

この記事の例では、テーブルを追加および削除するためのjsの具体的なコードを参考までに共有しています。...

CentOS 7 に PHP5 用の suPHP をインストールする方法 (Peng Ge)

デフォルトでは、CentOS 7 上の PHP は apache または nobody として実行さ...

スプレッド演算子のサンプルコードと JavaScript での応用

スプレッド演算子を使用すると、式をある時点で展開できます。スプレッド演算子は、複数のパラメーター (...

Linux で lvm 論理ボリューム パーティションのサイズを調整するチュートリアル (xfs や ext4 などのさまざまなファイル システム用)

序文システムをインストールしたときに、パーティション領域を適切に割り当てませんでした。その後のメンテ...

MySQL 8.0 WITH クエリの詳細

目次MySQL 8 の WITH クエリについて学ぶ1. 例3. 練習するMySQL 8 の WIT...

3分でUbuntu 16.04を初期化し、Java、Maven、Docker環境をデプロイする

Fast-Linux プロジェクト アドレス: https://gitee.com/uitc/Fas...

Linux CentOS 7.7 システムの VMware インストールに関する詳細なチュートリアル

Linux CentOS 7.7 システムを Vmware にインストールする方法。最小限のインスト...

Raspberry PiにDockerをインストールする方法

Raspberry Pi は ARM アーキテクチャをベースとしているため、Docker のインスト...

Nginx ドメイン転送の使用シナリオ コード例

シナリオ 1: サーバーの制限により、外部に開かれているポートは 1 つだけですが、別の外部ネットワ...

Linuxで新しいユーザーを作成し、指定されたディレクトリへの権限を付与する

1 ユーザーを作成し、ユーザーのルートパスとパスワードを指定します useradd -d /home...

要素シャトルフレームのパフォーマンス最適化の実装

目次背景解決新しい質問高度な背景シャトル ボックスが大量のデータを処理すると、レンダリングされる D...

レンダリング関数を使用して、拡張性の高いコンポーネントをカプセル化する

必要:バックグラウンド管理では、次のようなレイアウトでデータを表示する必要があることがよくあります。...