Zestawy znaków#
Kodowanie URL#
W dziale poświęconym odsyłaczom dokładnie opisałem budowę i znaczenie poszczególnych członów każdego adresu internetowego. W tej części przyjrzymy się znakom, które mogą być używane przy tworzeniu adresów URI/URL.
Adresy internetowe mogą być wysyłane w obrębie Internetu tylko za pomocą pewnej części znaków ASCII. Oznacza to, że wszystkie pozostałe znaki, lub znaki ASCII z tej części, których stosowanie w pewnym kontekście może wpłynąć na prawidłową budowę adresu, muszą zostać odpowiednio zakodowane.
Kodowanie URL (URL encoding), nazywane często kodowaniem procentowym (Percent encoding), jest mechanizmem służącym do kodowania znaków w URI (Uniform Resource Identifier), kiedy zajdzie taka potrzeba. Mimo że jest znane pod nazwą kodowanie URL, faktycznie jest wykorzystywane w ogólniejszej postaci URI, która zawiera jednocześnie URL (Uniform Resource Locator) oraz URN (Uniform Resource Name). URI jest terminem szerszym, stąd każdy URL jest URI, ale nie każdy URI jest URL. W praktyce obydwa terminy używa się zamiennie.
Rodzaje znaków w URI#
Zbiór prawidłowych znaków w adresach URI został okrojony. Dzieli się je na zarezerwowane (Reserved Characters) albo niezarezerwowane (Unreserved Characters). Występuje także specjalny znak procent ("%"), który jest częścią kodowania procentowego.
Zastrzeżone znaki są znakami o specjalnym przeznaczeniu, które wykorzystywane są do określania/rozdzielania poszczególnych części adresu URI. Dla przykładu, odwrócony ukośnik ("/") służy do oddzielania różnych części adresu internetowego. Niezarezerwowane znaki nie mają specjalnego przeznaczenia. Przy kodowaniu procentowym, znaki zastrzeżone zostają zastąpione specjalną sekwencją innych znaków. Zestaw znaków dozwolonych i zastrzeżonych zmieniał się nieznacznie w każdej specyfikacji dla URL/URI. Aktualny wykaz znajduje się w dokumencie RFC 3986 (sekcja 2.2 i sekcja 2.3).
Znaki zastrzeżone | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Znak | ! | # | $ | & | ' | ( | ) | * | + | , | / | : | ; | = | ? | @ | [ | ] |
Kod % | %21 | %23 | %24 | %26 | %27 | %28 | %29 | %2A | %2B | %2C | %2F | %3A | %3B | %3D | %3F | %40 | %5B | %5D |
Znaki dozwolone | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Znak | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z |
a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |||||||||||||||||
- | _ | . | ~ |
Znaki zastrzeżone (w zależności od kontekstu) oraz wszystkie inne spoza powyższych wykazów powinny zostać w odpowiedni sposób zakodowane.
Algorytm kodowania#
W adresach URI, znaki z zastrzeżonego zbioru należy zakodować tylko wtedy, kiedy mogą wpłynąć na budowę URI w danym kontekście. W tym celu należy użyć notacji procentowej:
%XX
gdzie "XX
" to liczba szesnastkowa kodowanego bajtu. Bajty mają reprezentować znaki w kodowaniu ASCII (zgodne z UTF-8 i innymi kodowaniami). Wielkość znaków w zapisie heksadecymalnym nie ma znaczenia. Obie formy będą poprawne: "%2F
" lub "%2f
".
W praktyce wystarczy wartość HEX (z tablicy dla ASCII) poprzedzić znakiem procentu, który w tym wypadku określany jest znakiem ucieczki lub uniku (escape character).
Co ciekawe, nie zawsze istnieje konieczność kodowania znaków zarezerwowanych, wszystko zależy od kontekstu. Przykładowo, po Query String (część po znaku "?"), znak "=" może zostać wstawiony jawnie, mimo że zaliczany jest do znaków zastrzeżonych. Ogólnie wszystko zależy od danego schematu URI (scheme URI), który jasno określa znaczenie każdego zarezerwowanego znaku w poszczególnych częściach adresu. Poniższy przykład będzie poprawny:
http://www.test.com/licz.php?section=piwo&sub=1
Znaki dozwolone nigdy nie powinny zostać zakodowane. Adresy URI, które różnią się tylko zapisem znaków dozwolonych (jawnie lub procentowo), nie zawsze uważane są przez procesory URI za równoważne. Dla zachowania maksymalnej kompatybilności zaleca się podawanie znaków dozwolonych tylko w postaci jawnej.
Ponieważ sam znak procenta ("%") wykorzystywany jest w kodowaniu, to w razie potrzeby należy go wprowadzić w postaci "%25".
Innym często spotykanym znakiem, który wymaga zakodowania jest spacja ("%20").
Dowolny znak#
Czasami może zajść potrzeba umieszczenia jakiegoś "egzotycznego" znaku (spoza ASCII). W takiej sytuacji znak procenta powinien pojawić się przed każdym bajtem (w danym kodowaniu). Będzie to dotyczyło wszystkich znaków, które składają się z dwóch lub większej liczby bajtów.
Obecnie najpopularniejszy zestaw znaków to Unicode (kodowanie UTF-8), dlatego też przykład oprę na tym kodowaniu. Powiedzmy, że w adresie URI umieszczone zostaną następujące dwa znaki:
U+20AC € (euro)
U+00B1 ± (plus-minus)
Najpierw musimy każdy kod znaku Unicode przedstawić za pomocą kodowania UTF-8. Można bawić się w ręczną konwersję, ale proponuję w tym celu wykorzystać jakieś dedykowane narzędzie, np. Graphemica. Wyniki przekształcenia będą następujące:
E2 82 AC € (euro)
C2 B1 ± (plus-minus)
Teraz, przed umieszczeniem znaków w adresie, wystarczy każdy bajt poprzedzić znakiem procentu ("%"):
<a href="#%E2%82%AC%C2%B1">Odsyłacz testowy kliknij!</a>
Efekt:
Odsyłacz testowy (kliknij!)Wystarczy kliknąć na powyższym odsyłaczu. Efekt działania zobaczymy w pasku adresowym przeglądarki - do aktualnego adresu dołączone zostaną znaki ("#€±"). Można też najechać na odsyłacz i zobaczyć jego pełne rozwinięcie na pasku adresowym przeglądarki lub dymku (na dole, w zależności od przeglądarki). Jak łatwo zauważyć, znaki pojawiły się w jawnej postaci. Jeśli spróbujemy skopiować i wkleić adres do edytora tekstowego, znaki zostaną wyrażone w kodowaniu procentowym.
Zwracam uwagę, że procenty wstawiamy przed bajtami z kodowania (np. UTF-8), a nie przed bajtami z zestawu Unicode (musimy dokonać konwersji). Konwersji nie musimy przeprowadzać w przypadku znaków ASCII, ponieważ dla tych znaków kody z Unicode (HEX) będą identyczne z rezultatem kodowania UTF-8 (HEX).
Typ application/x-www-form-urlencoded
#
Domyślnym typem danych (MIME) wysyłanych przez formularz jest application/x-www-form-urlencoded
. Nazwy oraz wartości kontrolek zostają zakodowane i wysłane za pomocą metody GET lub POST. Kodowanie dla tego typu danych oparte jest o bardzo wczesną wersje procentowego kodowania URI, z kilkoma modyfikacjami (np. spacja zostaje wprowadzona jako "+" zamiast "%20"). Ta przestarzała forma została przyjęta w specyfikacjach (X)HTML oraz XForms.
W przypadku metody GET zakodowane dane zostaną dołączone na końcu adresu strony docelowej jako Query String (klucz-wartość
). Przesyłane dane są widoczne dla użytkownika. W przypadku metody POST dane zostają umieszczone w ciele wiadomości, a typ danych MIME zostaje dołączony w nagłówku (Content-Type
) wiadomości.
Działanie w formularzach najłatwiej przeanalizować za pomocą wyszukiwarek (np. Google). Wystarczy wprowadzić jakąś ciekawą frazę (ze spacjami lub znakami spoza dozwolonego zakresu). Po zatwierdzeniu wyszukiwania (wysłanie metodą GET), w pasku adresowym przeglądarki pojawią się wysłane dane. Część z nich będzie odpowiadała za niektóre parametry (np. rozdzielczość ekranu), ale w gąszczu znaków powinniśmy odszukać kody procentowe tych, które sami wprowadziliśmy (uprzednio kopiując i wklejając adres do edytora).
Oto rezultat dla zapytania w postaci "dalej € ±":
https://www.google.pl/#hl=pl&gs_nf=1&cp=9&gs_id=e&xhr=t&q=dalej+%E2%82%AC+%C2%B1&pf=p&output=search&sclient=psy-ab&oq=dalej+%E2%82%AC+%C2%B1&gs_l=&pbx=1&bav=on.2,or.r_gc.r_pw.r_qf.,cf.osb&fp=6cc25fa17a160ec&biw=1920&bih=987
Jak łatwo zauważyć, zakodowanie znaków "€" oraz "±" (we wcześniejszym przykładzie) przeprowadzone zostało prawidłowo. W adresie Google widzimy, że faktycznie w przypadku formularzy spacje zamienione zostają na znaki ("+").
Przeglądarki#
Pisząc stronę internetową jest niemal pewne, że będzie ona zawierała chociaż jeden odsyłacz. Przy definiowaniu adresów (w kodzie źródłowym strony) możemy wstawić dowolne znaki. To przeglądarka przy analizie pliku (lub wysyłaniu/odbieraniu danych) przeprowadza odpowiednią konwersję (kodowanie procentowe). Wszystko, co opisałem do tej pory, miało na celu wyjaśnienie tego mechanizmu (a przynajmniej jego podstaw). Nasz przykładowy adres łącza możemy wpisać wprost:
<a href="#€±">Odsyłacz testowy kliknij!</a>
Efekt:
Odsyłacz testowy (kliknij!)Odpowiednie symbole automatycznie zostaną wyrażone za pomocą kodowania procentowego - wystarczy skopiować adres, by zobaczyć faktyczny efekt kodowania.
Funkcje w JavaScript#
W wielu językach programowania wprowadzono specjalne funkcje, które można wykorzystać do kodowania/dekodowania procentowego. W przypadku JS będą to globalne metody:
encodeURIComponent()
decodeURIComponent()
encodeURI()
decodeURI()
Pierwsza metoda koduje tylko te znaki ", / ? : ; @ & = + $ # [ ]" ze zbioru zastrzeżonego, oraz wszystkie spoza zbioru dozwolonych symboli - druga metoda jest jej odwrotnością. Trzecia metoda koduje tylko te znaki "[ ]" ze zbioru zastrzeżonego, oraz wszystkie spoza zbioru dozwolonych symboli - ostatnia metoda jest jej odwrotnością. Oto gotowy skrypt wyjaśniający różnice w działaniu, można uruchomić bezpośrednio w edytorze online:
<script type="text/javascript">
var adres = "http://www.test.com/licz.php?€ ±";
document.write(encodeURIComponent(adres));
// Rezultat: http%3A%2F%2Fwww.test.com%2Flicz.php%3F%E2%82%AC%20%C2%B1
document.write("<br>");
document.write(encodeURI(adres));
// Rezultat: http://www.test.com/licz.php?%E2%82%AC%20%C2%B1
</script>
Metoda decodeURIComponent()
może nam zastąpić polecenie decodeURI()
, ale sytuacja odwrotna zazwyczaj nie zwróci identycznych wyników.
Istnieją jeszcze metody escape()
oraz unascape()
, ale obecnie uważane są za przestarzałe i nie należy ich stosować. Kodowanie za pomocą escape()
przebiega na innej zasadzie niż w przypadku dwóch wcześniej prezentowanych metod. W tym wypadku wszystkie znaki zastrzeżone (prócz "+ * / @") oraz spoza zbioru dozwolonych symboli (prócz "~") zostaną zakodowane. Zakodowane znaki jednobajtowe zwracane są w postaci %X
, a wielobajtowe w postaci %uX
(gdzie "X" jest bezpośrednim kodem znaku Unicode, bez kodowania UTF-8). Przykładowo, dla znaku "€" zakodowaną postacią będzie %u20AC
, a dla znaku "±" kodem procentowym będzie %B1
.