Яка різниця між EscapeUriString та EscapeDataString?


195

Якщо ви маєте справу лише з кодуванням url, я повинен використовувати EscapeUriString ?


10
Завжди уникайте кожного окремого значення, використовуючи Uri.EscapeDataString(), як пояснено у відповіді @ Livven. При інших підходах система просто не має достатньо інформації для створення запланованого результату для кожного можливого введення.
Тимо

Відповіді:


112

Використовуйте EscapeDataStringзавжди (для отримання додаткової інформації про те, чому дивіться відповідь Ліввена нижче)

Редагувати : видалено мертве посилання на те, як вони відрізняються при кодуванні


3
Я не впевнений, що посилання насправді надає більше інформації, оскільки це стосується сканування карти, а не зникнення.
Стівен

1
Це в основному однакова різниця. Якщо ви насправді читаєте статтю, навколо середини стоїть таблиця, яка насправді виходить (а не на картинки), щоб показати відмінності (порівняно з URLEncodeзанадто).
Jcl

2
Мені все ще не зрозуміло - що робити, якщо я не уникаю цілого URI, а лише його частини - (тобто дані для параметра рядка запиту)? Чи я уникаю даних для URI, чи EscapeDataString означає щось зовсім інше?
BrainSlugs83

4
... Чи було тестування схоже, що я хочу EscapeDataString для параметра URI. Я тестував рядок "I heart C ++", і EscapeUriString не кодував символи "+", він просто залишив їх як є, EscapeDataString правильно перетворив їх у "% 2B".
BrainSlugs83

7
Це погана відповідь. Ніколи не слід використовувати EscapeUriString, це не має ніякого сенсу. Дивіться відповідь Ліввена нижче (і підкресліть її).
Брендон Паддок

243

Я не вважав наявні відповіді задовільними, тому вирішив заглибитись трохи глибше, щоб вирішити це питання. Дивно, але відповідь дуже проста:

Немає (майже *) поважних причин ніколи не використовувати Uri.EscapeUriString. Якщо вам потрібно кодувати рядок у відсотках, завжди використовуйте Uri.EscapeDataString.

* Дивіться останній абзац щодо дійсного випадку використання.

Чому це? Відповідно до документації :

Використовуйте метод EscapeUriString, щоб підготувати необмежену рядок URI, щоб бути параметром для конструктора Uri.

Це насправді не має сенсу. Відповідно до RFC 2396 :

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

Поки 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.EscapeUriStringне є магічним рішенням. Насправді це буде працювати у багатьох, якщо не в більшості випадків, але це аж ніяк не є надійним.

Ви завжди повинні будувати свої URL-адреси та рядки запитів, збираючи пари ключових значень і відсоткове кодування, а потім з'єднуючи їх з необхідними роздільниками. Ви можете використовувати Uri.EscapeDataStringдля цієї мети, але ні Uri.EscapeUriString, оскільки це не уникає зарезервованих символів, як зазначено вище.

Тільки якщо ви не можете цього зробити, наприклад, працюючи з наданими користувачем URI, має сенс використовувати Uri.EscapeUriStringв крайньому випадку. Але застосовуються раніше застереження - якщо URI, що надається користувачем, неоднозначний, результати можуть бути не бажаними.


4
Нічого собі, дякую, що остаточно прояснили це питання. Попередні дві відповіді були не дуже корисними.
EverPresent

3
Точно правильно. EscapeUriString (на зразок поведінки EscapeUrl за замовчуванням у Win32) був створений тим, хто не розумів URI-адреси або не врятувався. Це помилкова спроба створити щось, що спричинить неправильний URI, а іноді перетворити його на передбачувану версію. Але у нього немає інформації, яка потрібна для цього надійно. Він також часто звикає замість EscapeDataString, що також дуже проблематично. Я б хотів, щоб EscapeUriString не існував. Кожне його використання неправильне.
Брендон Паддок

4
чудово пояснено +1 - це краще, ніж прийнято лише відповідь на посилання
Ehsan Sajjad

1
Ця відповідь потребує більшої уваги. Це правильний спосіб зробити це. Інші відповіді мають сценарії, коли вони не дають намічених результатів.
Тимо

1
... Звичайно encodeURI/ Uri.EscapeUriStringне потрібно так часто, як encodeURIComponent/ Uri.EscapeDataString(оскільки коли ви здійснюєте деалінгування зі сліпими URL-адресами, які повинні використовуватися в урі-контексті), але це не означає, що воно не має свого місця.
Півмісяць свіжий

56

Символи плюс (+) можуть виявити багато про різницю між цими методами. У простому URI символ плюс означає "пробіл". Розглянемо запит Google щодо "щасливої ​​кішки":

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

Це дійсний URI (спробуйте його), і EscapeUriStringвін не змінює його.

Тепер розглянемо запит Google на "happy c ++":

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

Це дійсний URI (спробуйте), але він створює пошук "happy c", оскільки два плюси інтерпретуються як пробіли. Щоб виправити це, ми можемо передати "happy c ++" до EscapeDataStringі voila * :

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

*) Рядок закодованих даних насправді "щасливий% 20c% 2B% 2B"; % 20 - це шістнадцятковий символ для пробілу, а% 2B - шестнадцятковий для символу плюс.

Якщо ви використовуєте UriBuilderяк слід, тоді вам потрібно буде лише EscapeDataStringналежним чином уникнути деяких компонентів всього вашого URI. @ Відповідь Ліввена на це запитання ще більше доводить, що дійсно немає підстав для використання EscapeUriString.


Дякую. Що робити, наприклад, якщо у вас є абсолютна рядок URI, який потрібно кодувати, наприклад "https://www.google.com/?q=happy c++". Схоже, мені потрібно вручну розділити на "?", Чи є кращий спосіб?
wensveen

Якщо ви передаєте всю URL-адресу як параметр іншій URL-адресі, тоді використовуйте EscapeDataString. Якщо вказана вами URL-адреса є фактичною URL-адресою, то так, ви хочете просто розділити ?.
Сет

7

Коментарі в джерелі вирішують різницю чітко. Чому ця інформація не передається через коментарі документації XML, для мене загадка.

EscapeUriString:

Цей метод дозволить уникнути будь-якого символу, який не є зарезервованим або незарезервованим символом, включаючи знаки відсотків. Зауважте, що EscapeUriString також не уникатиме знаку "#".

EscapeDataString:

Цей метод дозволить уникнути будь-якого персонажа, який не є беззастережним символом, включаючи знаки відсотків.

Тому різниця полягає в тому, як вони поводяться із зарезервованими символами. EscapeDataStringтікає від них; EscapeUriStringне.

За даними RFC , зарезервовані символи::/?#[]@!$&'()*+,;=

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

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

Я не згоден із загальним поняттям, що EscapeUriStringце зло. Я думаю, що метод, який дозволяє уникати лише незаконних символів (наприклад, пробіли) і не зарезервовані символи, є корисним. Але у нього є химерність у тому, як він поводиться з %персонажем. Персонально закодовані символи ( %далі 2 шістнадцяткових цифр) є законними в URI. Думаю, 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
*/
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.