Если только иметь дело с URL-кодировкой, я должен использовать EscapeUriString ?
Если только иметь дело с URL-кодировкой, я должен использовать EscapeUriString ?
Ответы:
Используйте EscapeDataStringвсегда (для получения дополнительной информации о причинах см . Ответ Ливвена ниже)
Редактировать : удалена неработающая ссылка на то, как эти два кода различаются
URLEncode).
Я не нашел существующие ответы удовлетворительными, поэтому я решил немного углубиться, чтобы решить эту проблему. Удивительно, но ответ очень прост:
Нет (почти *) веской причины когда-либо использовать Uri.EscapeUriString. Если вам нужно процентное кодирование строки, всегда используйте Uri.EscapeDataString.
* См. Последний абзац для действительного варианта использования.
Почему это? Согласно документации :
Используйте метод EscapeUriString, чтобы подготовить неэкранированную строку 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, он игнорирует зарезервированные символы и экранирует только те символы, которые не являются ни зарезервированными, ни незарезервированными, что, кстати, противоречит документации . Таким образом, вы не получите ничего подобного http%3A%2F%2Fexample.org%2F, но в конечном итоге столкнетесь с проблемами, показанными выше.
В конце концов, если ваш URI действителен, его не нужно экранировать для передачи в качестве параметра создателю Uri, а если он недействителен, то вызов также Uri.EscapeUriStringне является волшебным решением. На самом деле, это будет работать во многих, если не в большинстве случаев, но отнюдь не надежно.
Вы всегда должны создавать свои URL-адреса и строки запросов, собирая пары ключ-значение и процентное кодирование, а затем объединяя их с необходимыми разделителями. Вы можете использовать Uri.EscapeDataStringдля этой цели, но не Uri.EscapeUriString, так как это не экранирует зарезервированные символы, как упомянуто выше.
Только если вы не можете этого сделать, например, когда имеете дело с пользовательскими URI, имеет смысл использовать Uri.EscapeUriStringв качестве последнего средства. Но применяются ранее упомянутые предостережения - если предоставленный пользователем URI является неоднозначным, результаты могут быть нежелательны.
encodeURI/ Uri.EscapeUriStringне нужно так часто, как encodeURIComponent/ Uri.EscapeDataString(так как, когда вы опаздываете со слепыми URL-адресами, которые должны использоваться в контексте URI), но это не значит, что ему не место.
Символы плюс (+) могут многое рассказать о разнице между этими методами. В простом URI символ «плюс» означает «пробел». Подумайте о том, чтобы запросить у Google «счастливый кот»:
Это действительный URI (попробуйте), и EscapeUriStringон не будет изменен.
Теперь рассмотрим запрос Google на «счастливый c ++»:
Это действительный URI (попробуйте), но он производит поиск «happy c», потому что два плюса интерпретируются как пробелы. Чтобы это исправить, мы можем передать "happy c ++" EscapeDataStringи вуаля * :
*) Закодированная строка данных на самом деле "happy% 20c% 2B% 2B"; % 20 - шестнадцатеричный символ пробела, а% 2B - шестнадцатеричный символ плюса.
Если вы используете, UriBuilderкак вы должны, то вам нужно только EscapeDataStringправильно экранировать некоторые компоненты вашего URI. Ответ @ Ливвена на этот вопрос еще раз доказывает, что нет никаких оснований для использования EscapeUriString.
"https://www.google.com/?q=happy c++". Похоже, мне нужно вручную разделить на "?", Или есть лучший способ?
EscapeDataString. Если указанный вами URL-адрес является фактическим, то да, вы хотите просто разделить его ?.
Комментарии в источнике четко указывают на разницу. Почему эта информация не передается в комментариях к документации XML, для меня загадка.
EscapeUriString:
Этот метод будет экранировать любой символ, который не является зарезервированным или незарезервированным символом, включая знаки процента. Обратите внимание, что EscapeUriString также не будет экранировать знак «#».
EscapeDataString:
Этот метод будет экранировать любой символ, который не является незарезервированным символом, включая знаки процента.
Так что разница в том, как они обрабатывают зарезервированные символы. EscapeDataStringизбегает их; EscapeUriStringне.
Согласно RFC , зарезервированные символы::/?#[]@!$&'()*+,;=
Для полноты, незарезервированные символы являются буквенно-цифровыми и -._~
Оба метода экранируют символы, которые не являются ни зарезервированными, ни незарезервированными.
Я не согласен с общим представлением, что EscapeUriStringэто зло. Я думаю, что метод, который экранирует только недопустимые символы (например, пробелы) и незарезервированные символы, является полезным. Но у него есть своеобразие в том, как он обращается с %персонажем. Символы в процентах ( %за которыми следуют 2 шестнадцатеричных цифры) являются допустимыми в URI. Я думаю, что EscapeUriStringбыло бы гораздо полезнее, если бы он обнаружил этот шаблон и избегал кодирования, %когда сразу же идут две шестнадцатеричные цифры.
Простой пример
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
*/
Uri.EscapeDataString(), как описано в ответе @ Livven. При других подходах система просто не имеет достаточно информации для получения ожидаемого результата для каждого возможного ввода.