Kodowanie URL zamienia znak na znak procentu i dwie cyfry szesnastkowe: spacja zmienia się w %20, ampersand w %26, znak zapytania w %3F. Cel jest taki, żeby znak nie został odczytany jako składnia URL, kiedy miał być danymi. Nic więcej.
Wydaje się to trudniejsze, niż jest, bo prawie każde pytanie o kodowanie URL jest w istocie pytaniem o zakres. Które znaki, w której części URL-a, zakodowane przez którą warstwę? Źle ustalony zakres daje jeden z dwóch klasycznych błędów: parametr śledzący, który po cichu się ucina, albo miejsce docelowe, które przychodzi jako https%3A%2F%2Fexample.com i zwraca 404. Ten artykuł opisuje dwa zbiory znaków, które decydują o odpowiedzi, miejsca, gdzie zasady się zmieniają, i jak sprawdzić, co link faktycznie niesie. Szerszy obraz tego, co robi z tym wszystkim przekierowanie, opisują typy przekierowań.
Dwa zbiory, które decydują o wszystkim
RFC 3986, sekcja 2.3 definiuje zbiór unreserved, który nigdy nie wymaga kodowania: litery, cyfry i dokładnie cztery znaki interpunkcyjne - myślnik, kropkę, podkreślenie, tyldę. Jeśli twoja wartość zawiera tylko takie znaki, nie musisz robić nic.
Wszystko inne wpada w jeden z dwóch koszyków. Znaki reserved niosą znaczenie strukturalne: : / ? # [ ] @ rozdzielają części URL-a, a ! $ & ' ( ) * + , ; = rozdzielają rzeczy wewnątrz tych części. Sekcja 2.2 je wymienia. Są legalne jako składnia i muszą być kodowane, kiedy występują jako dane. Reszta to wszystko poza ASCII, co jest kodowane bajt po bajcie po konwersji do UTF-8 - dlatego jedna litera z akcentem kosztuje zwykle sześć znaków, a nie trzy.
To daje jedyną zasadę, którą warto zapamiętać: koduj znak, kiedy jest danymi i inaczej zostałby odczytany jako składnia. Ampersand między dwoma parametrami to składnia. Ampersand wewnątrz nazwy kampanii to dane, i jeśli go nie zakodujesz, lista parametrów kończy się właśnie tam.
Koduj wartość, nie URL
To błąd, który widzę najczęściej, i zawsze ma tę samą postać. Ktoś ma URL, wie, że trzeba go zakodować, więc wkleja całość do encodera i dostaje:
https%3A%2F%2Fexample.com%2Fspring%3Futm_campaign%3Dspring%20sale
Ten ciąg nie jest URL-em. To kawałek tekstu w kształcie URL-a, który może być tylko wartością wewnątrz innego URL-a - co jest właśnie tym miejscem, gdzie należy, kiedy przekazujesz miejsce docelowe przez redirector, i właśnie tym miejscem, gdzie nie należy, kiedy próbujesz go otworzyć.
Poprawne podejście koduje każdą wartość osobno:
https://example.com/spring?utm_campaign=spring%20sale&utm_source=flyer
Schemat, host, separatory ścieżki oraz ? i & zostają jako składnia. Zmieniła się tylko wartość. Każdy język ma dwie funkcje do tego rozróżnienia, i wybranie tej niewłaściwej to druga połowa problemu: strona MDN o encodeURIComponent mówi bez ogródek, że encodeURI celowo zostawia zarezerwowane znaki bez zmian, bo oczekuje całego URI, podczas gdy encodeURIComponent je koduje, bo oczekuje jego fragmentu. Wartości chcą encodeURIComponent. W Pythonie to urllib.parse.quote, w Go url.QueryEscape, w PHP rawurlencode.
Spacja to %20, poza miejscami, gdzie jest plusem
Obie formy są prawidłowe, w różnych miejscach, i to jest zdecydowanie najbardziej zagmatwana rzecz w tym temacie.
W ścieżce albo w ogólnym URI spacja to %20. W query string zbudowanym tak, jak buduje go formularz HTML, spacja to +, bo tak właśnie definiuje to serializacja application/x-www-form-urlencoded w standardzie URL WHATWG. Obie formy są odczytywane jako spacja przez każdy parser query po stronie serwera, na jaki prawdopodobnie natrafisz.
Pułapka jest w drugą stronę. Jeśli znak plus jest danymi - numer telefonu, wyszukiwana fraza, kampania nazwana spring+summer - trzeba go zapisać jako %2B. Zostawiony bez zmian w query string zmienia się w spację, i spędzisz popołudnie, zastanawiając się, czemu numer w twoim CRM zgubił kod kraju.
| Znak | Zakodowany | Czemu to ma znaczenie |
|---|---|---|
| spacja | %20 lub + | + tylko wewnątrz query string, %20 wszędzie |
& | %26 | Niezakodowany, lista parametrów kończy się właśnie tam |
? | %3F | Niezakodowany, wszystko po nim staje się query |
# | %23 | Niezakodowany, reszta nigdy nie trafia do serwera |
+ | %2B | Niezakodowany w query, przychodzi jako spacja |
% | %25 | Niezakodowany, następne dwa znaki zostają zjedzone |
Wiersz # zasługuje na uwagę, bo to on generuje najbardziej zagmatwane zgłoszenia błędów. Fragment nigdy nie jest wysyłany do serwera. Umieść niezakodowany # w miejscu docelowym przekierowania, i serwer zobaczy ucięty URL, podczas gdy pole adresu w przeglądarce wciąż wygląda dobrze, więc osoba zgłaszająca problem przysięga, że link działa.
Jeśli budujesz URL-e kampanii ręcznie częściej niż od czasu do czasu, przestań: nasz UTM builder koduje każdą wartość na bieżąco, a konwencje nazewnictwa UTM opisują wybieranie wartości, które od razu nie wymagają kodowania. Skróć wynik na własnej domenie, i zakodowany bałagan przestaje być czymś, na co ktokolwiek musi patrzeć.
Podwójne kodowanie i jak je zauważyć
Podwójne kodowanie zdarza się, kiedy wartość przechodzi przez dwie warstwy, z których każda robi swoje. Sam znak procentu jest znakiem, który trzeba kodować, więc %20 zmienia się w %2520, a %2520 w %252520.
Symptomy da się rozpoznać, kiedy się je już raz widziało. Tytuł strony wyświetlający spring%20sale prawdziwemu odwiedzającemu. Parametr, który przychodzi do analityki z widocznymi sekwencjami ucieczki. Przekierowanie, które działa przy pierwszym skoku i zawodzi przy drugim. Przyczyną jest prawie zawsze wywołanie kodujące owinięte wokół wartości, która przyszła już zakodowana, często bo wyszła z bazy danych, która przechowywała zakodowaną formę.
Naprawa polega na tym, żeby zdecydować, która warstwa jest odpowiedzialna za kodowanie, i uczynić inne bezdotykowymi. Dekoduj raz, kiedy czytasz wartość, koduj raz, kiedy zapisujesz ją do URL-a, i nigdy nie rób obu w tej samej funkcji.
Gdzie to najbardziej boli w praktyce
Trzy miejsca, w kolejności, w jakiej najprawdopodobniej je spotkasz.
Parametry śledzące. Wartość kampanii z niezakodowanym ampersandem ucina listę parametrów, więc sesja trafia do twojej analityki jako ruch bezpośredni, a kampania nie dostaje żadnego uznania. Nic się nie wywala. Parametry UTM nie pokazują się w GA4 opisuje diagnozę ze strony raportowania, a przeglądarki usuwają parametry UTM opisuje drugi powód, dla którego parametr może zniknąć między kliknięciem a stroną.
Przekierowania. Reguły serwera kodują ponownie niekonsekwentnie, a to, czy query string w ogóle przetrwa, zależy od użytej dyrektywy. Przekierowanie 301 w .htaccess ma pełną tabelę dla Apache; w skrócie: reguła, która zamienia query string, po cichu upuści twój.
Kody QR. Kodowanie zwiększa długość payloadu, a długość payloadu decyduje o tym, jak gęsty jest wydrukowany kod. Każda spacja kosztuje trzy znaki zamiast jednego, każda litera z akcentem sześć. URL śledzący z kilkoma zakodowanymi nazwami kampanii może przesunąć kod o wersję albo dwie wyżej, co jest realną różnicą w rozmiarze wizytówki - kod QR się nie skanuje właśnie z tego powodu umieszcza długość payloadu wśród czterech przyczyn. Zakodowanie krótkiego linku zamiast całego URL-a to najtańsza dostępna naprawa.
Sprawdź, co link faktycznie niesie
Dwie komendy rozstrzygają prawie każdy spór. Pierwsza pokazuje, co dostaje serwer po przekierowaniu:
curl -sI 'https://example.com/spring?utm_campaign=spring%20sale' | grep -i '^location'
Druga buduje kodowanie za ciebie, zamiast liczyć na twoje palce, co jest przydatne, kiedy wartość zawiera kilku winowajców naraz:
curl -G --data-urlencode 'utm_campaign=spring & summer sale' \
--data-urlencode 'utm_source=flyer' \
-o /dev/null -w '%{url_effective}\n' https://example.com/spring
Czytaj wynik jako dane, nie jako dekorację. Jeśli widzisz %2520, masz problem z podwójnym kodowaniem, jeśli widzisz wartość kończącą się przedwcześnie, masz niezakodowany separator, a jeśli widzisz %3A%2F%2F na początku, zakodowałeś cały URL. Nasz link checker robi część z przekierowaniem w przeglądarce, jeśli nie chcesz otwierać terminala.
Zwyczaj, który warto sobie wyrobić, to spojrzeć na finalny URL raz, na własne oczy, zanim kampania wystartuje. Błędy kodowania są niewidoczne w przeglądarce i oczywiste w terminalu, i kosztują cię atrybucję, nie uptime, dlatego przetrwają tak długo.
Przeczytaj serię filarową
Ten artykuł należy do klastra inżynieryjnego. Po stronę przekierowań, typy przekierowań opisuje każdy kod statusu i metodę po stronie klienta, a jak działają skracacze URL opisuje, co dzieje się między kliknięciem a stroną.
Powiązane na blogu
- Parametry UTM wyjaśnione, ze schematem nazewnictwa, który przetrwa
- Parametry UTM nie pokazują się w GA4? Wyjaśniamy czemu
- Przekierowanie 301 w .htaccess: reguły, kolejność, query stringi
- Jak skrócić URL w Pythonie za pomocą biblioteki requests
- Kod QR się nie skanuje? Cztery przyczyny i jak je naprawić
Najczęściej zadawane pytania
Co to jest kodowanie URL?
Zamiana znaku na znak procentu, po którym następuje jego wartość bajtowa w systemie szesnastkowym, tak żeby znak nie mógł zostać pomylony ze składnią URL. Spacja zmienia się w %20, ampersand w %26, znak zapytania w %3F. Mechanizm definiuje RFC 3986, nazywa się też percent-encoding.
Które znaki trzeba kodować w URL?
Wszystko poza zbiorem unreserved, który RFC 3986 definiuje jako litery, cyfry i cztery znaki: myślnik, kropkę, podkreślenie i tyldę. Wszystko inne to albo zarezerwowana interpunkcja niosąca znaczenie strukturalne, albo bajt spoza ASCII, i oba przypadki muszą być zakodowane procentowo, kiedy występują wewnątrz wartości, a nie jako składnia.
Czy powinienem kodować cały URL, czy tylko jego części?
Tylko części. Przepuszczenie całego URL-a przez encoder zmienia https://example.com w https%3A%2F%2Fexample.com, co w ogóle nie jest już URL-em. Koduj każdą wartość parametru query i każdy segment ścieżki osobno, a schemat, host i separatory zostaw bez zmian.
Spacja to %20 czy znak plus?
Jedno i drugie, w różnych miejscach. W ścieżce i w ogólnym URI spacja to %20. W query string zbudowanym tak, jak buduje go formularz HTML, spacja to znak plus, bo tak właśnie definiuje to serializacja application/x-www-form-urlencoded. Dosłowny plus wewnątrz wartości query trzeba więc zapisać jako %2B, bo inaczej zostanie odczytany jako spacja.
Co to jest podwójne kodowanie?
Zakodowanie czegoś, co było już zakodowane, przez co %20 zmienia się w %2520, bo sam znak procentu zostaje zamieniony na %25. Symptomem jest strona wyświetlająca dosłowne %20 w tekście albo parametr, który przychodzi z widocznymi sekwencjami ucieczki. To prawie zawsze wartość przechodząca przez dwie warstwy, z których każda usłużnie ją zakodowała.
Czemu zakodowane znaki utrudniają skanowanie kodu QR?
Bo każdy z nich kosztuje trzy znaki zamiast jednego. Spacja to jeden znak intencji i trzy znaki payloadu, więc kilka z nich może przesunąć kod o wersję albo dwie wyżej, co znaczy więcej modułów na tej samej powierzchni druku. Zakodowanie długiego URL-a śledzącego w kod QR to jeden z najszybszych sposobów na zrobienie kodu, który skanuje się tylko z bliskiej odległości.
Wypróbuj Elido
Wklej URL, otrzymaj krótki link
Bez rejestracji. Link działa 30 dni. Zarejestruj się, aby zachować go na zawsze.
Za darmo, bez rejestracji · 2 dziennie