Який правильний спосіб кодувати URL-символи Unicode?


107

Я знаю про нестандартну схему% uxxxx, але це не здається мудрим вибором, оскільки W3C цю схему було відхилено.

Кілька цікавих прикладів:

Характер серця. Якщо я введіть це у свій браузер:

http://www.google.com/search?q=♥

Потім скопіюйте та вставте, я бачу цю URL-адресу

http://www.google.com/search?q=%E2%99%A5

завдяки чому здається, що це робить Firefox (або Safari).

urllib.quote_plus(x.encode("latin-1"))
'%E2%99%A5'

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

Якщо я введу URL-адресу

http://www.google.com/search?q=…

у свій браузер потім копіюю та вставляю, я отримую

http://www.google.com/search?q=%E2%80%A6

назад. Який, здається, результат виконання

urllib.quote_plus(x.encode("utf-8"))

що має сенс, оскільки ... не може бути закодовано з латинською-1.

Але тоді мені не зрозуміло, як браузер знає, чи потрібно розшифровувати UTF-8 або Latin-1.

Оскільки це здається неоднозначним:

In [67]: u"…".encode('utf-8').decode('latin-1')
Out[67]: u'\xc3\xa2\xc2\x80\xc2\xa6'

працює, тому я не знаю, як браузер з'ясовує, чи розшифровувати це за допомогою UTF-8 або Latin-1.

Що правильно робити з особливими персонажами, з якими мені потрібно мати справу?


19
Обидва ваші приклади кодуються як UTF-8. Перший, звичайно, не латинський-1, враховуючи, що це три байти ...
Якоб Борг,

2
% E2% 99% A5 - це шістнадцять значень байтів для "костюма чорного серця" в UTF-8 . Це чорне серце не є частиною набору символів "Латинська-1" .
Хокі Паркер

Щоб надійно побачити, як і що кодує браузер (та багато іншої корисної інформації), використовуйте інструменти для розробників, вбудовані в більшість сучасних браузерів, або отримайте безкоштовний налагоджувач HTTP, як Fiddler .
Хокі Паркер

Відповіді:


65

Я б завжди кодував UTF-8. На сторінці Вікіпедії про відсоткове кодування :

Загальний синтаксис URI вимагає, щоб нові схеми URI, які передбачають представлення символьних даних в URI, фактично повинні представляти символи з незарезервованого набору без перекладу, і повинні перетворювати всі інші символи в байти відповідно до UTF-8, а потім відсотків-кодують ці значення. Ця вимога була введена в січні 2005 року з публікацією RFC 3986 . Схеми URI, запроваджені до цієї дати, не впливають.

Схоже, тому, що раніше існували інші прийняті способи кодування URL-адрес, браузери намагаються застосувати кілька методів декодування URI, але якщо ви кодуєте цей код, вам слід скористатися UTF-8.


8
UTF-8 також слід використовувати, оскільки це єдине кодування, дозволене новішим стандартом IRI (RFC 3987, tools.ietf.org/html/rfc3986 ), яке замінює старіший стандарт URL-адреси.
Ремі Лебо

3
У випадку, якщо інші настільки здивовані, як і я, текст у коментарі @ RemyLebeau зазначає RFC3987, але посилання на старішу специфікацію 3896. Правильна URL-адреса, очевидно, tools.ietf.org/html/rfc3987
tripleee

Так, вибачте з цього приводу. URI визначено RFC 3986, IRI визначено RFC 3987.
Remy Lebeau

10

Загальним правилом, здається, є те, що браузери кодують відповіді форми відповідно до типу вмісту сторінки, з якої надано форму. Це здогадка, що якщо сервер надсилає нам "text / xml; charset = iso-8859-1", вони очікують відповіді ще в тому ж форматі.

Якщо ви просто вводите URL-адресу в рядку URL-адреси, у веб-переглядача немає базової сторінки, над якою можна працювати, і тому просто потрібно здогадуватися. Тож у цьому випадку, здається, весь час робиться utf-8 (оскільки обидва ваші входи давали триоктні значення форми).

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

Загальновідома проблема полягає в тому, що вам потрібно повідомити серверну основу, який набір символів ви очікуєте, що рядок запиту буде закодовано як --- наприклад, у Tomcat, ви повинні викликати request.setEncoding () (або якийсь подібний метод) перед вами зателефонуйте до будь-якого із методів request.getParameter (). Недостатня кількість документації з цього приводу, ймовірно, відображає недостатню обізнаність про проблему серед багатьох розробників. (Я регулярно запитую респондентів Java, яка різниця між Reader та InputStream, і регулярно отримую порожні вигляди)


6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) визначає стандартне кодування - UTF-8 повинен використовуватися при кодуванні символів, які інакше не дозволено некодувати.
Ремі Лебо

8

IRI ( RFC 3987 ) - це останній стандарт, який замінює стандарти URI / URL ( RFC 3986 і новіші ). URI / URL не підтримують Unicode (ну, RFC 3986 додає положення для майбутніх протоколів на основі URI / URL для його підтримки, але не оновлює минулі RFC). Схема "% uXXXX" - це нестандартне розширення для дозволу Unicode в деяких ситуаціях, але не застосовується універсально для всіх. IRI, з іншого боку, повністю підтримує Unicode, і вимагає, щоб текст кодувався як UTF-8, перш ніж бути відсотковим.


Я хочу побачити оновлення протоколів, щоб Unicode повністю підтримувався в URL-адресах, а не лише через відсоткове кодування.
Матьє Дж.

1
IRI дозволяє використовувати некодовані символи Unicode, за винятком кількох випадків, коли зарезервовані символи повинні бути закодовані.
Ремі Лебо

6

IRI не замінюють URI, тому що лише URI (фактично, ASCII) допустимі в деяких контекстах - включаючи HTTP.

Замість цього ви вказуєте IRI, і він перетворюється на URI, коли виходить на провід.


0

Перше питання - які ваші потреби? Кодування UTF-8 - це досить хороший компроміс між прийняттям тексту, створеного за допомогою дешевого редактора, та підтримкою широкого спектру мов. Що стосується браузера, що ідентифікує кодування, відповідь (з веб-сервера) повинна повідомити браузеру про кодування. Ще більшість браузерів намагаються здогадатися, оскільки це відсутність або помилка в дуже багатьох випадках. Вони здогадуються, прочитавши деяку кількість потоку результатів, щоб побачити, чи є символ, який не входить у кодування за замовчуванням. В даний час усі браузери (я цього не перевіряв, але він досить близький до істинного) використовують utf-8 як типовий.

Тому використовуйте utf-8, якщо у вас немає переконливих причин використовувати одну з багатьох інших схем кодування.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.