Jaki jest właściwy sposób kodowania znaków Unicode w adresie URL?

107

Znam niestandardowy schemat% uxxxx, ale nie wydaje się to mądrym wyborem, ponieważ schemat został odrzucony przez W3C.

Kilka interesujących przykładów:

Charakter serca. Jeśli wpiszę to w przeglądarce:

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

Następnie skopiuj i wklej, widzę ten adres URL

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

co sprawia, że ​​wygląda na to, że Firefox (lub Safari) to robi.

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

co ma sens, z wyjątkiem rzeczy, których nie można zakodować w Latin-1, takich jak znak potrójnej kropki.

Jeśli wpiszę adres URL

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

do mojej przeglądarki, a następnie kopiuj i wklej, otrzymuję

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

plecy. Co wydaje się być wynikiem działania

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

co ma sens, ponieważ… nie można go zakodować za pomocą Latin-1.

Ale wtedy nie jest dla mnie jasne, skąd przeglądarka wie, czy dekodować za pomocą UTF-8, czy Latin-1.

Ponieważ wydaje się to niejednoznaczne:

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

działa, więc nie wiem, w jaki sposób przeglądarka ustala, czy dekodować to za pomocą UTF-8 czy Latin-1.

Co należy zrobić z postaciami specjalnymi, z którymi mam do czynienia?

Josh Gibson
źródło
19
Oba twoje przykłady są zakodowane jako UTF-8. Pierwszy z pewnością nie Latin-1, biorąc pod uwagę, że ma trzy bajty ...
Jakob Borg
2
% E2% 99% A5 to szesnastkowe wartości bajtów „koloru czarnego serca” w UTF-8 . To czarne serce nie jest częścią zestawu znaków Latin-1 .
Hawkeye Parker
Aby dokładnie zobaczyć, jak i co koduje przeglądarka (i wiele innych przydatnych informacji), użyj narzędzi programistycznych wbudowanych w większość nowoczesnych przeglądarek lub pobierz darmowy debugger HTTP, taki jak Fiddler .
Hawkeye Parker

Odpowiedzi:

65

Zawsze kodowałbym w UTF-8. Ze strony Wikipedii na temat kodowania procentowego :

Ogólna składnia URI wymaga, aby nowe schematy URI, które zapewniają reprezentację danych znakowych w identyfikatorze URI, muszą w efekcie reprezentować znaki z niezastrzeżonego zestawu bez tłumaczenia i powinny konwertować wszystkie inne znaki na bajty zgodnie z UTF-8, a następnie kod procentowy tych wartości. Wymóg ten został wprowadzony w styczniu 2005 r. Wraz z publikacją RFC 3986 . Nie ma to wpływu na schematy URI wprowadzone przed tą datą.

Wygląda na to, że w przeszłości istniały inne akceptowane sposoby kodowania adresów URL, przeglądarki próbują kilku metod dekodowania identyfikatora URI, ale jeśli to Ty kodujesz, powinieneś użyć UTF-8.

John Biesnecker
źródło
8
Należy również użyć UTF-8, ponieważ jest to jedyne kodowanie dozwolone w nowszym standardzie IRI (RFC 3987, tools.ietf.org/html/rfc3986 ), które zastępuje starszy standard adresów URL.
Remy Lebeau
3
Na wypadek, gdyby inni byli tak samo zaskoczeni jak ja, tekst w komentarzu @ RemyLebeau wspomina o RFC3987, ale odsyłacz prowadzi do starszej specyfikacji 3896. Prawidłowy adres URL to oczywiście tools.ietf.org/html/rfc3987
tripleee
Tak, przepraszam za to. Identyfikator URI jest zdefiniowany w dokumencie RFC 3986, IRI w dokumencie RFC 3987.
Remy Lebeau
10

Wydaje się, że ogólna zasada jest taka, że ​​przeglądarki kodują odpowiedzi z formularzy zgodnie z typem zawartości strony, z której formularz został udostępniony. To jest przypuszczenie, że jeśli serwer wyśle ​​nam "text / xml; charset = iso-8859-1", to oczekuje odpowiedzi w tym samym formacie.

Jeśli po prostu wpisujesz adres URL w pasku adresu URL, to przeglądarka nie ma strony bazowej do pracy i dlatego musi tylko odgadnąć. Więc w tym przypadku wydaje się, że wykonuje utf-8 przez cały czas (ponieważ oba twoje dane wejściowe wyprodukowały trzyoktetowe wartości).

Smutną prawdą jest to, że AFAIK nie ma standardu określającego, jaki zestaw znaków wartości w ciągu zapytania, a nawet jakiekolwiek znaki w adresie URL, powinny być interpretowane jako. Przynajmniej w przypadku wartości w ciągu zapytania, nie ma powodu, aby przypuszczać, że oni muszą zrobić odpowiadają znaków.

Jest to znany problem polegający na tym, że musisz powiedzieć swojemu środowisku serwerowemu, który zestaw znaków oczekujesz, że ciąg zapytania zostanie zakodowany jako --- na przykład w Tomcat musisz wywołać request.setEncoding () (lub inną podobną metodę) przed tobą wywołaj dowolną z metod request.getParameter (). Brak dokumentacji na ten temat prawdopodobnie odzwierciedla brak świadomości problemu wśród wielu programistów. (Regularnie pytam respondentów Java, jaka jest różnica między czytnikiem a InputStream i regularnie otrzymuję puste spojrzenia)

araqnid
źródło
6
RFC 3987 ( tools.ietf.org/html/rfc3986 ) definiuje standardowe kodowanie - przy kodowaniu znaków, które w innym przypadku nie są dozwolone jako niezakodowane, należy używać UTF-8.
Remy Lebeau
8

IRI ( RFC 3987 ) to najnowszy standard, który zastępuje standardy URI / URL ( RFC 3986 i starsze). URI / URL nie obsługują natywnie Unicode (cóż, RFC 3986 dodaje przepisy dla przyszłych protokołów opartych na URI / URL, aby je obsługiwać, ale nie aktualizuje poprzednich RFC). Schemat „% uXXXX” jest niestandardowym rozszerzeniem zezwalającym w niektórych sytuacjach na Unicode, ale nie jest powszechnie stosowany przez wszystkich. Z drugiej strony IRI w pełni obsługuje Unicode i wymaga zakodowania tekstu jako UTF-8, zanim zostanie zakodowany procentowo.

Remy Lebeau
źródło
Chciałbym zobaczyć aktualizację protokołów, aby Unicode były w pełni obsługiwane w adresach URL, nie tylko przez kodowanie procentowe.
Mathieu J.
1
IRI zezwalają na niezakodowane znaki Unicode, z wyjątkiem nielicznych przypadków, w których należy zakodować znaki zastrzeżone.
Remy Lebeau
6

IRI nie zastępują URI, ponieważ tylko URI (w rzeczywistości ASCII) są dozwolone w niektórych kontekstach - w tym HTTP.

Zamiast tego określasz IRI i jest on przekształcany w identyfikator URI, gdy wychodzi przez sieć.

Mark Nottingham
źródło
0

Pierwsze pytanie brzmi: jakie są Twoje potrzeby? Kodowanie UTF-8 to całkiem niezły kompromis pomiędzy pobieraniem tekstu utworzonego w tanim edytorze a obsługą wielu różnych języków. Jeśli chodzi o przeglądarkę identyfikującą kodowanie, odpowiedź (z serwera WWW) powinna poinformować przeglądarkę o kodowaniu. Wciąż większość przeglądarek będzie próbowała zgadywać, ponieważ w wielu przypadkach tego brakuje lub jest błędne. Zgadują, czytając pewną ilość strumienia wyników, aby sprawdzić, czy istnieje znak, który nie pasuje do domyślnego kodowania. Obecnie wszystkie przeglądarki (? Nie sprawdzałem tego, ale jest to całkiem bliskie prawdy) domyślnie używają utf-8.

Więc używaj utf-8, chyba że masz nieodparty powód, aby użyć jednego z wielu innych schematów kodowania.

Pat O
źródło