EscapeUriStringとEscapeDataStringの違いは何ですか?


192

URLエンコードのみを処理する場合は、EscapeUriStringを使用する必要がありますか?


10
@Livvenの回答で説明されているように、常に個々のをを使用してエスケープしUri.EscapeDataString()ます。他のアプローチでは、システムはすべての可能な入力に対して意図された結果を生成するのに十分な情報を持っていません。
Timo

回答:


112

EscapeDataString常に使用(理由の詳細については、以下のLivvenの回答を参照)

編集:2つのエンコーディングの違いへのデッドリンクを削除


3
リンクがエスケープではなくエスケープ解除に関するものであるため、リンクが実際に詳細情報を提供するかどうかはわかりません。
Steven

1
基本的には同じ違いです。記事を実際に読んだ場合、違いを示すために(あまりエスケープしないで)実際にエスケープする中央付近の表があります(URLEncodeあまりにも比較しています)。
Jcl 2013

2
それは私にはまだはっきりしていません-URI全体をエスケープせず、その一部のみをエスケープする場合-(つまり、クエリ文字列パラメータのデータ)?URIのデータをエスケープしていますか、それともEscapeDataStringはまったく異なるものを意味していますか?
BrainSlugs83 2013年

4
...一部のテストは、URIパラメータにEscapeDataStringが必要なように見えました。文字列「I heart C ++」でテストしましたが、EscapeUriStringは「+」文字をエンコードせず、そのままにしました。EscapeDataStringは、それらを「%2B」に正しく変換しました。
BrainSlugs83 2013年

7
これは悪い答えです。EscapeUriStringは絶対に使用しないでください。意味がありません。以下のLivvenの回答を参照してください(そしてそれを賛成投票してください)。
Brandon Paddock、2016

241

既存の回答で満足できる結果が得られなかったため、この問題を解決するためにもう少し掘り下げることにしました。驚いたことに、答えは非常に簡単です。

(ほとんど*)を使用する正当な理由はありませんUri.EscapeUriString。文字列をパーセントエンコードする必要がある場合は、常にを使用してくださいUri.EscapeDataString

*有効な使用例については、最後の段落を参照してください。

どうしてこれなの?ドキュメントによると:

EscapeUriStringメソッドを使用して、エスケープされていないURI文字列をUriコンストラクターのパラメーターとして準備します。

これは実際には意味がありません。RFC 2396によると:

完成したURIをエスケープまたはエスケープ解除するとセマンティクスが変わる可能性があるため、URIは常に「エスケープ」形式になります。

引用されたRFCはRFC 3986によって廃止されましたが、要点はまだ残っています。いくつかの具体例を見て確認しましょう。

  1. 次のような単純なURIがあります。

    http://example.org/

    Uri.EscapeUriString 変更されません。

  2. エスケープを考慮せずに、クエリ文字列を手動で編集することにしました。

    http://example.org/?key=two words

    Uri.EscapeUriString (正しく)スペースをエスケープします:

    http://example.org/?key=two%20words
  3. さらに、クエリ文字列を手動で編集することにしました。

    http://example.org/?parameter=father&son

    ただし、この文字列はUri.EscapeUriStringアンパサンドが別のキーと値のペアの開始を表すと想定しているため、では変更されません。これは、意図したものである場合とそうでない場合があります。

  4. 実際にはkeyパラメーターをにしたいと判断したfather&sonので、アンパサンドをエスケープして、以前のURLを手動で修正します。

    http://example.org/?parameter=father%26son

    ただし、Uri.EscapeUriStringパーセント文字もエスケープし、二重エンコードにつながります。

    http://example.org/?parameter=father%2526son

ご覧のとおりUri.EscapeUriString、意図した目的で使用する&と、複数のキーと値のペア間の区切り文字としてではなく、クエリ文字列のキーまたは値の一部として使用できなくなります。

これは、完全なURIをエスケープするのに適したものにするために、予約文字を無視して、予約も予約もされていない文字のみをエスケープするためです。BTWは、ドキュメントに反しています。このようにすると、のような結果http%3A%2F%2Fexample.org%2Fになることはありませんが、上記の問題が発生します。


結局のところ、URIが有効であれば、それをエスケープしてパラメーターとしてUriコンストラクターに渡す必要はありません。また、URIが有効でない場合、呼び出しUri.EscapeUriStringも魔法の解決策ではありません。実際、ほとんどの場合ではなくても多くの場合に機能しますが、信頼できるとは限りません。

キーと値のペアとパーセントエンコーディングを収集し、それらを必要な区切り記号で連結することにより、常にURLとクエリ文字列を作成する必要があります。上記のように予約文字をエスケープしないため、Uri.EscapeDataStringこの目的には使用できますが、には使用できUri.EscapeUriStringません。

ユーザー提供のURIを処理する場合など、それができない場合にのみUri.EscapeUriString、最後の手段として使用することは理にかなっています。ただし、前述の警告が適用されます。ユーザーが指定したURIが不明確な場合、結果が望ましくない場合があります。


4
わあ、この問題を最終的に明らかにしてくれてありがとう。前の2つの回答はあまり役に立ちませんでした。
EverPresent 2015

3
その通りです。EscapeUriString(Win32でのEscapeUrlのデフォルトの動作と同様)は、URIやエスケープを理解していない人によって作成されました。これは、不正な形式のURIをとるものを作成し、するために見当違いの試みだ時には意図バージョンにそれを回します。しかし、これを確実に行うために必要な情報がありません。また、EscapeDataStringの代わりに頻繁に使用されますが、これも非常に問題があります。EscapeUriStringが存在しなかったといいのですが。それのすべての使用は間違っています。
ブランドンパドック、2016

4
うまく説明された+1承認されたリンクのみの回答よりもはるかに優れています
Ehsan Sajjad

1
この答えにはもっと注意が必要です。それを行う正しい方法です。他の回答には、意図した結果が得られないシナリオがあります。
Timo

1
...確かにencodeURI/ Uri.EscapeUriStringが多いほど必要とされていないencodeURIComponent/ Uri.EscapeDataString(あなたは、URIのコンテキストで使用されなければならないブラインドURLをdeaingされたとき以来の)、それはその場所を持っていないという意味ではありません。
クレセントフレッシュ

56

プラス(+)文字は、これらの方法の違いを明らかにします。単純なURIでは、プラス記号は「スペース」を意味します。「ハッピーキャット」についてGoogleにクエリすることを検討してください:

https://www.google.com/?q=happy+cat

これは有効なURI(試してみてください)であり、EscapeUriString変更することはありません。

次に、Googleに「ハッピーc ++」をクエリすることを検討してください。

https://www.google.com/?q=happy+c++

これは有効なURIです(試してみてください)。ただし、2つのプラス記号はスペースとして解釈されるため、「ハッピーc」を検索します。それを修正するために、我々は「幸せなC ++」に渡すことができEscapeDataString出来上がり*を

https://www.google.com/?q=happy+c%2B%2B

*)エンコードされたデータ文字列は、実際には「happy%20c%2B%2B」です。%20はスペース文字の16進数で、%2Bはプラス文字の16進数です。

本来の方法で使用しUriBuilderている場合は、EscapeDataStringURI全体の一部のコンポーネントを適切にエスケープするだけで済みます。この質問に対する@Livvenの回答は、実際に使用する理由がないことをさらに証明していますEscapeUriString


ありがとう。たとえば、エンコードする必要がある絶対URI文字列がある場合はどうでしょうか"https://www.google.com/?q=happy c++"。「?」で手動で分割する必要があるようですが、もっと良い方法はありますか?
wensveen 2015年

URL全体をパラメータとして別のURLに渡す場合は、を使用しますEscapeDataString。指定したURLが実際のURLである場合、はい、そのまま分割し?ます。
Seth

7

ソース内のコメントは、違いを明確に示しています。なぜこの情報がXMLドキュメントのコメントを介して提供されないのかは、私には謎です。

EscapeUriString:

このメソッドは、パーセント記号を含め、予約済みまたは未予約の文字ではない文字をエスケープします。EscapeUriStringも「#」記号をエスケープしないことに注意してください。

EscapeDataString:

このメソッドは、パーセント記号など、予約されていない文字以外の文字をエスケープします。

したがって、違いは、予約文字の処理方法にありますEscapeDataStringそれらをエスケープします。EscapeUriStringではない。

RFCによれば、予約文字は次のとおりです。:/?#[]@!$&'()*+,;=

完全を期すため、予約されていない文字は英数字と -._~

どちらの方法でも、予約済みでも予約済みでもない文字をエスケープします。

私は一般的に反対概念EscapeUriString悪です。予約文字ではなく、不正な文字(スペースなど)のみをエスケープする方法が便利だと思います。しかし、それはそれがキャラクターを処理する方法に奇妙な点を持っています。パーセントエンコードされた文字(その後に2桁の16進数)は、URIで有効です。このパターンが検出され、すぐに2桁の16進数が続く場合はエンコードを回避すると、はるかに役立つと思います。%%EscapeUriString%


1

簡単な例

var data = "example.com/abc?DEF=あいう\x20えお";

Console.WriteLine(Uri.EscapeUriString(data));
Console.WriteLine(Uri.EscapeDataString(data));
Console.WriteLine(System.Net.WebUtility.UrlEncode(data));
Console.WriteLine(System.Web.HttpUtility.UrlEncode(data));

/*
=>
example.com/abc?DEF=%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86%20%E3%81%88%E3%81%8A
example.com%2Fabc%3FDEF%3D%E3%81%82%E3%81%84%E3%81%86+%E3%81%88%E3%81%8A
example.com%2fabc%3fDEF%3d%e3%81%82%e3%81%84%e3%81%86+%e3%81%88%e3%81%8a
*/
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.