Я не нашел существующие ответы удовлетворительными, поэтому я решил немного углубиться, чтобы решить эту проблему. Удивительно, но ответ очень прост:
Нет веских причин использовать 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
, так как он не экранирует зарезервированные символы, как упоминалось выше.