Если только иметь дело с 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. При других подходах система просто не имеет достаточно информации для получения ожидаемого результата для каждого возможного ввода.