Varje del av en URL och vad den får innehålla

Varje del av en URL utpekad i ett genomgånget exempel, vilka tecken som måste procentkodas var, hur frågesträngar faktiskt beter sig, och hur du upptäcker en länk som ljuger om sin värd.

En URL är en enda sträng som talar om vilket protokoll som ska talas, vilken maskin det ska talas med och vad som ska efterfrågas. Att läsa en korrekt handlar mest om att veta var varje del slutar, eftersom avgränsarna är enstaka tecken och den första vinner.

https://alex:s3cret@www.example.co.uk:8443/docs/intro?lang=en&page=2#notes
│       │           │                 │   │           │              └─ fragment
│       │           │                 │   │           └──────────────── query
│       │           │                 │   └──────────────────────────── path
│       │           │                 └──────────────────────────────── port
│       │           └────────────────────────────────────────────────── host
│       └────────────────────────────────────────────────────────────── userinfo
└────────────────────────────────────────────────────────────────────── scheme

Delarna

DelAvgränsas avVad den är till förNår servern
Schemaslutar vid första :Vilket protokoll och vilka regler som gäller för restenAvgör anslutningen
Userinfoefter //, slutar vid @Inloggningsuppgifter, sedan länge avrådda för http och httpsBara om klienten väljer att skicka dem
Värdslutar vid :, /, ? eller #Ett domännamn eller en IP-adress att slå upp och ansluta tillJa, i Host-huvudet
Portefter :, slutar vid /, ? eller #TCP-porten, som utan angivelse är 80 för http och 443 för httpsAnvänds för anslutningen
Sökvägbörjar vid /, slutar vid ? eller #Vilken resurs på den värdenJa, i begäranraden
Frågesträngbörjar vid ?, slutar vid #Parametrar till den resursenJa, i begäranraden
Fragmentbörjar vid #, löper till slutetEn plats inuti resursenNej

Värd och port utgör tillsammans auktoriteten. Fragmentet är undantaget: det tas bort innan begäran byggs, så en server ser det aldrig. Webbläsare använder det för ankare och routing på klientsidan, och vissa autentiseringsflöden returnerar medvetet tokens i ett fragment så att dessa tokens aldrig hamnar i en serverlogg. Det hamnar ändå i webbläsarhistoriken, så det är inte privat, bara oskickat.

Reserverade och oreserverade tecken

Procentkodning skriver en byte som % plus två hexadecimala siffror, utifrån teckenets UTF-8-bytes. é blir %C3%A9, två bytes och två escape-sekvenser.

Fyra tecken är oreserverade vid sidan av bokstäver och siffror, och behöver aldrig kodas någonstans: - . _ ~. Allt annat är antingen reserverat, vilket betyder att det har en strukturell uppgift någonstans i en URL, eller måste kodas. Den reserverade mängden är : / ? # [ ] @ samt ! $ & ' ( ) * + , ; =.

Ordet "reserverat" betyder inte "alltid förbjudet". Det betyder att tecknet är en avgränsare i någon del, och att det måste kodas bara i de delar där det skulle läsas som en avgränsare.

TeckenI ett sökvägssegmentI ett frågevärde
Mellanslag%20, alltid%20 eller +
/%2F, annars delas segmentetTillåtet som det är
?%3F, annars slutar sökvägen därTillåtet som det är
#%23, alltid%23, alltid
& och =Tillåtna som de är%26 och %3D, annars delas paret
+Tillåtet, och betyder ett plustecken%2B, annars kan det avkodas som ett mellanslag

Det är den praktiska regeln: koda det tecken som skulle avsluta den del du befinner dig i. Ett mellanslag i en sökväg måste vara %20, eftersom ett rått mellanslag avslutar URL:en i de flesta parsrar, medan ett mellanslag i ett frågevärde kan vara %20 eller det äldre +. En URL Encoder är det tillförlitliga sättet att göra detta, eftersom att koda en hel URL och att koda en enskild komponent är två olika operationer och den andra är nästan alltid den som avses.

Frågesträngar är en konvention

Specifikationen säger bara att frågesträngen är allt mellan ? och #, hämtat ur de tillåtna tecknen. Formen key=value&key=value kommer från HTML:s formulärkodning, inte från URI-standarden. Ingenting hindrar en server från att tolka ?a:1;b:2 precis som den vill.

Eftersom formen är en konvention har upprepade nycklar ingen definierad innebörd, och varje stack valde sitt eget svar:

Beteende för ?id=1&id=2Var
Båda värdena, som en listaPython parse_qs, Node querystring, Express
Bara första värdetGo Query().Get, Java getParameter
Bara sista värdetPHP, Rails
Sammanfogade till 1,2ASP.NET request collections

Arrayer ärver samma problem. ids=1&ids=2, ids[]=1&ids[]=2, ids[0]=1&ids[1]=2 och ids=1,2 används alla flitigt, och bara servern avgör vilken av dem den förstår. Hakparentesnotationen måste kodas för att vara strikt tillåten (ids%5B%5D=1), även om de flesta servrar accepterar råa hakparenteser. Välj den form som mottagarsidan dokumenterar, och håll dig sedan konsekvent till den.

Plustecknet förtjänar en egen varning. I data av typen application/x-www-form-urlencoded, alltså en formulärkodad begärankropp, betyder + ett mellanslag. I en URL-sökväg betyder det ett bokstavligt plustecken. I en frågesträng beror det på parsern, och de flesta webbramverk tillämpar formuläravkodning där, så + blir tyst ett mellanslag. Varje värde som legitimt kan innehålla ett plus, till exempel vanlig Base64-utdata eller ett telefonnummer, måste skickas som %2B.

Relativa referenser

En relativ referens löses upp mot en bas-URL genom att allt efter basens sista / byts ut. Det sista snedstrecket är hela regeln, och det är därför ett avslutande snedstreck spelar roll.

BasReferensResultat
https://ex.com/docs/introguidehttps://ex.com/docs/guide
https://ex.com/docs/intro/guidehttps://ex.com/docs/intro/guide
https://ex.com/docs/intro/guidehttps://ex.com/guide
https://ex.com/docs/intro/../guidehttps://ex.com/docs/guide
https://ex.com/docs/intro?a=1?b=2https://ex.com/docs/intro?b=2
https://ex.com/docs/intro?a=1#tophttps://ex.com/docs/intro?a=1#top
https://ex.com/docs/intro//cdn.ex.com/x.jshttps://cdn.ex.com/x.js

Den sista raden är en schemarelativ referens: två inledande snedstreck behåller basens schema och ersätter auktoriteten. En referens som börjar med ? behåller sökvägen och kastar den gamla frågesträngen, och en som börjar med # behåller båda.

När två URL:er är samma resurs

Schema och värd är skiftlägesokänsliga, så HTTPS://Example.COM och https://example.com är en och samma adress. Allt efter värden är skiftlägeskänsligt så långt standarden är berörd, även om en viss server väljer att bortse från skiftläge.

Dessa par är likvärdiga:

  • https://example.com:443/a och https://example.com/a, eftersom porten är standardporten
  • https://example.com och https://example.com/, eftersom en tom sökväg betyder roten
  • /a/%7Euser och /a/~user, eftersom ~ är oreserverat och att procentkoda det inte ändrar något

Dessa par är det inte:

  • /docs och /docs/, som är olika resurser, även om de flesta servrar omdirigerar den ena till den andra
  • /p?a=1&b=2 och /p?b=2&a=1, eftersom parameterordningen är en del av strängen
  • /index.html och /, om inte servern säger annat

Cachar och CDN:er nycklar på de exakta bytesen, så en tillagd spårningsparameter eller en omkastad frågesträng delar upp ett cachat objekt i två och halverar träffkvoten. Sökmotorer behandlar varianterna som dubblettsidor om inte en kanonisk länk pekar ut en vald form. Lösningen är att välja en enda form, omdirigera resten till den med en 301 och rensa bort parametrar som inte påverkar svaret.

Längd, loggar och integritet

Ingen längdgräns finns i specifikationen, men gränser finns överallt annars. Vanliga serverstandarder begränsar hela begäranraden till omkring 8 KB, vissa proxyservrar och nätverksenheter till 4 KB och äldre klienter till runt 2 KB. Allt som måste överleva e-postklienter, QR-koder och länkförkortare är säkrast under omkring 2000 tecken.

Det starkare argumentet för att hålla URL:er korta är att en frågesträng inte är privat. Den skrivs in i åtkomstloggar, skickas vidare till tredje part i Referer-huvudet, bevaras i webbläsarhistoriken, sparas med bokmärken och kopieras varje gång någon delar länken. Sessionstokens, koder för lösenordsåterställning, API-nycklar och personuppgifter hör därför inte hemma där. Data som är stora eller känsliga läggs i en begärankropp, som inte har något praktiskt storlekstak och inte loggas som standard.

Att läsa en länk innan du klickar på den

Auktoriteten börjar efter :// och slutar vid allra första /, ? eller #. Läs det avsnittet, och läs sedan dess två eller tre sista etiketter. Det är den verkliga värden, och ingenting till vänster om den ändrar den.

https://www.paypal.com@198.51.100.7/secure/login
        ^^^^^^^^^^^^^^ ^^^^^^^^^^^^
        userinfo       real host

Vanlig utstyrsel att känna igen:

  • Text före ett @ är userinfo, aldrig värden, och den kan vara vilket varumärkesnamn som helst.
  • paypal.com.secure-login.example är en subdomän till secure-login.example. Etiketter läses från höger till vänster.
  • https://short.example/https://www.bank.com/login lägger en hel övertygande URL i sökvägen.
  • En värd som börjar med xn-- är Punycode, ASCII-formen av ett internationaliserat domännamn framställd av IDNA. münchen.de är xn--mnchen-3ya.de på tråden, vilket är legitimt, men samma mekanism möjliggör homografer: kyrilliskt а (U+0430) är visuellt identiskt med latinskt a, och en domän som använder det kodas till något i stil med xn--pple-43d.com. Webbläsare visar Punycode-formen när en etikett blandar skriftsystem, men reglerna varierar och är ingen garanti.
  • Kodade avgränsare som %2F eller %40 inuti en värd är ett medvetet försök att förvirra en parser.

Att klistra in länken i en URL Parser avgör saken i ett enda steg, eftersom en riktig parser tillämpar samma regel om att första avgränsaren vinner som webbläsaren kommer att göra, och visar värden för sig. För att kontrollera många länkar samtidigt är en Regex Tester ett snabbt sätt att bekräfta vilka av dem som faktiskt har den auktoritet du förväntar dig.