Какая разница между EscapeUriString и EscapeDataString?

Если вы имеете дело только с кодировкой url, я должен использовать EscapeUriString?

Ответы

Ответ 1

EscapeDataString используйте EscapeDataString (для получения дополнительной информации о причинах см. Ответ Livven ниже)

Редактировать: удалена неработающая ссылка на то, как эти два кода различаются

Ответ 2

Я не нашел удовлетворительных ответов, поэтому решил немного углубиться, чтобы решить эту проблему. Удивительно, но ответ очень прост:

Нет действительной причины когда-либо использовать Uri.EscapeUriString. Если вам нужно кодировать строку в процентах, всегда используйте Uri.EscapeDataString.

Почему это? Согласно документации :

Используйте метод EscapeUriString, чтобы подготовить строку unescaped URI как параметр для конструктора Uri.

Это не имеет смысла. Согласно RFC 2396:

URI всегда находится в "экранированной" форме, поскольку экранирование или удаление завершенного URI может изменить его семантику.

Пока цитируемый RFC был устарел RFC 3986, точка все еще стоит. Проверим это, посмотрев на некоторые конкретные примеры:

  • У вас есть простой URI, например:

    http://example.org/
    

    Uri.EscapeUriString не изменит его.

  • Вы решили вручную отредактировать строку запроса без учета экранирования:

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

    Uri.EscapeUriString (правильно) освободит место для вас:

    http://example.org/?key=two%20words
    
  • Вы также решите вручную отредактировать строку запроса:

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

    Однако эта строка не изменяется на Uri.EscapeUriString, так как предполагается, что амперсанд означает начало другой пары ключ-значение. Это может быть или не быть тем, что вы намеревались.

  • Вы решили, что на самом деле хотите, чтобы параметр 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 construtor, и если он недействителен, вызов Uri.EscapeUriString также не является волшебным решением. Фактически, он будет работать во многих случаях, если не в большинстве случаев, но он ни в коем случае не является надежным.

Вы всегда должны создавать свои URL-адреса и строки запроса, собирая пары ключ-значение и процентное кодирование, а затем объединяя их с необходимыми разделителями. Вы можете использовать Uri.EscapeDataString для этой цели, но не Uri.EscapeUriString, так как он не пропускает зарезервированные символы, как указано выше.

Ответ 3

Символы плюса (+) могут показать многое о различии между этими методами. В простом URI символ плюса означает "пространство". Рассмотрите запрос Google для "счастливой кошки":

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

Что действительный URI (попробуйте), а EscapeUriString не будет изменять его.

Теперь рассмотрим запрос Google для "happy С++":

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

Это допустимый URI (попробуйте), но он производит поиск "happy c", потому что два плюса интерпретируются как пробелы. Чтобы исправить это, мы можем передать "happy С++" на EscapeDataString и voila *:

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

*) Строка закодированных данных фактически "счастлива %20c% 2B% 2B"; %20 - hex для символа пробела, а% 2B - шестнадцатеричный для символа плюса.

Если вы используете UriBuilder, как и должно быть, вам понадобится EscapeDataString только для правильного удаления некоторых компонентов всего вашего URI. @Livven ответ на этот вопрос еще раз доказывает, что на самом деле нет причин использовать EscapeUriString.

Ответ 4

Комментарии в источнике четко указывают на разницу. Почему эта информация не передается в комментариях к документации XML, для меня загадка.

EscapeUriString:

Этот метод будет экранировать любой символ, который не является зарезервированным или незарезервированным символом, включая знаки процента. Обратите внимание, что EscapeUriString также не будет экранировать знак "#".

EscapeDataString:

Этот метод будет экранировать любой символ, который не является незарезервированным символом, включая знаки процента.

Так что разница в том, как они обрабатывают зарезервированные символы. EscapeDataString избегает их; EscapeUriString нет.

Согласно RFC, зарезервированными символами являются:: :/?#[]@!$&'()*+,;=

Для полноты, незарезервированные символы являются буквенно-цифровыми и -._~

Оба метода экранируют символы, которые не являются ни зарезервированными, ни незарезервированными.

Я не согласен с общим представлением, что EscapeUriString является злом. Я думаю, что метод, который экранирует только недопустимые символы (например, пробелы) и незарезервированные символы, является полезным. Но у него есть особенность в том, как он обрабатывает символ %. Символы в % (% за которыми следуют 2 шестнадцатеричные цифры) являются допустимыми в URI. Я думаю, что EscapeUriString был бы гораздо более полезным, если бы он обнаружил этот шаблон и избегал кодирования % когда он сразу продолжался с 2 шестнадцатеричными цифрами.

Ответ 5

Простой пример

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
*/