Každá část URL a co smí obsahovat
URL je jeden řetězec, který říká, jakým protokolem se má mluvit, s jakým strojem a na co se má zeptat. Přečíst ji správně je hlavně otázka toho, vědět, kde která část končí, protože oddělovači jsou jednotlivé znaky a rozhoduje ten první.
https://alex:s3cret@www.example.co.uk:8443/docs/intro?lang=en&page=2#notes
│ │ │ │ │ │ └─ fragment
│ │ │ │ │ └──────────────── query
│ │ │ │ └──────────────────────────── path
│ │ │ └──────────────────────────────── port
│ │ └────────────────────────────────────────────────── host
│ └────────────────────────────────────────────────────────────── userinfo
└────────────────────────────────────────────────────────────────────── scheme
Jednotlivé části
| Část | Ohraničena | K čemu slouží | Dorazí na server |
|---|---|---|---|
| Schéma | končí u prvního : | Jaký protokol a jaká pravidla platí pro zbytek | Určuje spojení |
| Userinfo | za //, končí u @ | Přihlašovací údaje, u http a https dávno zastaralé | Jen pokud se je klient rozhodne odeslat |
| Host | končí u :, /, ? nebo # | Doménové jméno nebo IP adresa, kterou je třeba přeložit a připojit se k ní | Ano, v hlavičce Host |
| Port | za :, končí u /, ? nebo # | TCP port, výchozí 80 pro http a 443 pro https | Použije se pro spojení |
| Cesta | začíná u /, končí u ? nebo # | Který zdroj na daném hostu | Ano, v řádku požadavku |
| Dotaz | začíná u ?, končí u # | Parametry pro daný zdroj | Ano, v řádku požadavku |
| Fragment | začíná u #, jde až do konce | Místo uvnitř zdroje | Ne |
Host a port dohromady tvoří autoritu. Fragment je výjimka: odstraní se ještě před sestavením požadavku, takže ho server nikdy neuvidí. Prohlížeče ho používají pro kotvy a směrování na straně klienta a některé autentizační postupy záměrně vracejí tokeny ve fragmentu, aby se tyto tokeny nikdy neobjevily v logu serveru. Stejně ale skončí v historii prohlížeče, takže není soukromý, jen se neodesílá.
Vyhrazené a nevyhrazené znaky
Procentové kódování zapisuje bajt jako % a dvě hexadecimální číslice, přičemž vychází z UTF-8 bajtů daného znaku. Z é se stane %C3%A9, dva bajty a dvě escape sekvence.
Vedle písmen a číslic jsou nevyhrazené čtyři znaky, které se nikde kódovat nemusí: - . _ ~. Všechno ostatní je buď vyhrazené, což znamená, že to má někde v URL strukturní úlohu, nebo se to musí zakódovat. Vyhrazená množina je : / ? # [ ] @ a ! $ & ' ( ) * + , ; =.
Slovo „vyhrazený“ neznamená „vždy zakázaný“. Znamená, že znak je v některé části oddělovačem a kódovat se musí jen v těch částech, kde by se jako oddělovač četl.
| Znak | V segmentu cesty | V hodnotě dotazu |
|---|---|---|
| Mezera | %20, vždy | %20 nebo + |
/ | %2F, jinak rozdělí segment | Legální tak, jak je |
? | %3F, jinak tam cesta končí | Legální tak, jak je |
# | %23, vždy | %23, vždy |
& a = | Legální tak, jak jsou | %26 a %3D, jinak se dvojice rozpadne |
+ | Legální a znamená plus | %2B, jinak se může dekódovat jako mezera |
To je to praktické pravidlo: zakódujte znak, který by ukončil část, ve které se právě nacházíte. Mezera v cestě musí být %20, protože nezakódovaná mezera ve většině parserů URL ukončí, zatímco mezera v hodnotě dotazu může být %20 nebo starší +. Spolehlivý způsob, jak to udělat, je URL Encoder, protože zakódovat celou URL a zakódovat jednu její komponentu jsou dvě různé operace a téměř vždy je potřeba ta druhá.
Dotazovací řetězce jsou konvence
Specifikace říká jen to, že dotaz je všechno mezi ? a #, složené z povolených znaků. Tvar key=value&key=value pochází z kódování HTML formulářů, ne ze standardu URI. Nic nebrání serveru, aby si ?a:1;b:2 parsoval, jak se mu zlíbí.
Protože je tento tvar jen konvence, opakované klíče nemají definovaný význam a každý ekosystém si zvolil vlastní odpověď:
Chování pro ?id=1&id=2 | Kde |
|---|---|
| Obě hodnoty jako seznam | Python parse_qs, Node querystring, Express |
| Jen první hodnota | Go Query().Get, Java getParameter |
| Jen poslední hodnota | PHP, Rails |
Spojené do 1,2 | Kolekce požadavků v ASP.NET |
Pole dědí stejný problém. ids=1&ids=2, ids[]=1&ids[]=2, ids[0]=1&ids[1]=2 i ids=1,2 se všechny běžně používají a jen server rozhoduje, kterému z nich rozumí. Zápis s hranatými závorkami se musí zakódovat, aby byl přísně vzato legální (ids%5B%5D=1), i když většina serverů nezakódované závorky přijme. Vyberte tvar, který dokumentuje přijímající strana, a pak ho dodržujte.
Znaménko plus si zaslouží vlastní varování. V datech application/x-www-form-urlencoded, tedy v těle požadavku zakódovaném jako formulář, znamená + mezeru. V cestě URL znamená doslovné plus. V dotazovacím řetězci to závisí na parseru a většina webových frameworků tam formulářové dekódování aplikuje, takže se z + tiše stane mezera. Každá hodnota, která legitimně může obsahovat plus, například standardní výstup Base64 nebo telefonní číslo, se musí posílat jako %2B.
Relativní odkazy
Relativní odkaz se vyhodnotí vůči základní URL tak, že se nahradí všechno za posledním / v základní URL. To poslední lomítko je celé pravidlo a právě proto na koncovém lomítku záleží.
| Základ | Odkaz | Výsledek |
|---|---|---|
https://ex.com/docs/intro | guide | https://ex.com/docs/guide |
https://ex.com/docs/intro/ | guide | https://ex.com/docs/intro/guide |
https://ex.com/docs/intro | /guide | https://ex.com/guide |
https://ex.com/docs/intro/ | ../guide | https://ex.com/docs/guide |
https://ex.com/docs/intro?a=1 | ?b=2 | https://ex.com/docs/intro?b=2 |
https://ex.com/docs/intro?a=1 | #top | https://ex.com/docs/intro?a=1#top |
https://ex.com/docs/intro | //cdn.ex.com/x.js | https://cdn.ex.com/x.js |
Poslední řádek je odkaz relativní vůči schématu: dvě úvodní lomítka zachovají schéma základní URL a nahradí autoritu. Odkaz, který začíná na ?, zachová cestu a zahodí původní dotaz, a odkaz, který začíná na #, zachová obojí.
Kdy jsou dvě URL týž zdroj
Schéma a host nerozlišují velikost písmen, takže HTTPS://Example.COM a https://example.com jsou jedna adresa. Všechno za hostem velikost písmen podle standardu rozlišuje, i když se konkrétní server může rozhodnout ji ignorovat.
Tyto dvojice jsou ekvivalentní:
https://example.com:443/aahttps://example.com/a, protože port je výchozíhttps://example.comahttps://example.com/, protože prázdná cesta znamená kořen/a/%7Eusera/a/~user, protože~je nevyhrazený a jeho procentové zakódování nic nemění
Tyto dvojice ekvivalentní nejsou:
/docsa/docs/, což jsou různé zdroje, i když většina serverů jeden na druhý přesměruje/p?a=1&b=2a/p?b=2&a=1, protože pořadí parametrů je součástí řetězce/index.htmla/, pokud server neurčí jinak
Cache a CDN klíčují podle přesných bajtů, takže přidaný sledovací parametr nebo přeházený dotaz rozdělí jeden uložený objekt na dva a sníží úspěšnost cache na polovinu. Vyhledávače považují varianty za duplicitní stránky, dokud kanonický odkaz neukáže na jeden zvolený tvar. Řešením je vybrat jediný tvar, zbytek na něj přesměrovat pomocí 301 a odstranit parametry, které odpověď nemění.
Délka, logy a soukromí
Specifikace žádný limit délky nestanoví, ale limity existují všude jinde. Běžné výchozí konfigurace serverů omezují celý řádek požadavku zhruba na 8 KB, některé proxy a hardwarová zařízení na 4 KB a starší klienti asi na 2 KB. Cokoli, co musí přežít e-mailové klienty, QR kódy a zkracovače odkazů, je nejbezpečnější pod zhruba 2000 znaky.
Silnější argument pro krátké URL je ten, že dotazovací řetězec není soukromý. Zapisuje se do přístupových logů, předává se třetím stranám v hlavičce Referer, zůstává v historii prohlížeče, ukládá se se záložkami a kopíruje se pokaždé, když někdo odkaz sdílí. Relační tokeny, kódy pro reset hesla, API klíče a osobní údaje tam proto nepatří. Data, která jsou objemná nebo citlivá, patří do těla požadavku, které nemá praktický strop velikosti a ve výchozím nastavení se neloguje.
Jak si přečíst odkaz, než na něj kliknete
Autorita začíná za :// a končí u úplně prvního /, ? nebo #. Přečtěte si tento úsek a pak jeho poslední dvě nebo tři části. To je skutečný host a nic nalevo od něj na tom nic nemění.
https://www.paypal.com@198.51.100.7/secure/login
^^^^^^^^^^^^^^ ^^^^^^^^^^^^
userinfo real host
Běžné maskování, které je dobré poznat:
- Text před
@je userinfo, nikdy ne host, a může to být naprosto libovolné jméno značky. paypal.com.secure-login.exampleje subdoménou doménysecure-login.example. Části domény se čtou zprava doleva.https://short.example/https://www.bank.com/loginvkládá celou přesvědčivou URL do cesty.- Host začínající na
xn--je Punycode, tedy ASCII podoba internacionalizovaného doménového jména vytvořená pomocí IDNA.münchen.deje na drátěxn--mnchen-3ya.de, což je legitimní, ale stejný mechanismus umožňuje homografy: cyrilskéа(U+0430) je vizuálně totožné s latinskýmaa doména, která ho použije, se zakóduje na něco jakoxn--pple-43d.com. Prohlížeče zobrazují podobu v Punycode, když se v jedné části domény mísí různá písma, jenže pravidla se liší a nejsou zárukou. - Zakódované oddělovače jako
%2Fnebo%40uvnitř hostu jsou záměrným pokusem zmást parser.
Vložení odkazu do nástroje URL Parser to vyřeší v jednom kroku, protože skutečný parser aplikuje stejné pravidlo „vyhrává první oddělovač“ jako prohlížeč a host zobrazí samostatně. Při kontrole mnoha odkazů najednou je Regex Tester rychlý způsob, jak ověřit, které z nich skutečně mají autoritu, kterou očekáváte.