HTTP
HTTP (Hypertext Transfer Protocol) är språket som webbläsare och webbservrar talar med varandra. Allt du bygger i den här kursen tar emot HTTP-förfrågningar och skickar HTTP-svar, så det här är veckans viktigaste sida. Den innehåller:
- samspelet mellan klient och server
- en URL:s delar
- hur förfrågningar och svar ser ut
- metoder, statuskoder och headers
- hur data skickas till servern
- cookies, och hur en server kan komma ihåg en användare
- HTTPS och certifikat
- verktygen för att se vad som skickas
- övningar att göra på egen hand
Läs sidan Nätverk först. HTTP är det sista av de fyra stegen från URL till svar som beskrivs där.
Tidsåtgång: Ungefär 25–30 minuter att läsa och en och en halv timme för övningarna.
Klient, server och tillståndslöshet
Section titled “Klient, server och tillståndslöshet”I HTTP är det alltid klienten som börjar. Den skickar en förfrågan (request), och
servern svarar med ett svar (response). Klienten är oftast en webbläsare, men kan lika gärna
vara curl, en mobilapp eller din egen Node-app som anropar ett API.
HTTP är tillståndslöst (stateless): varje förfrågan är fristående, och servern minns ingenting från den förra. Det gör att en server kan hantera väldigt många klienter, och att förfrågningar kan fördelas mellan flera servrar. Men det gör också att inloggning inte fungerar av sig själv. Hur det ändå löses tar avsnittet om cookies upp.
En URL:s delar
Section titled “En URL:s delar”https://coursepress.lnu.se:443/kurser/sok?q=http&sida=2#resultat└─┬─┘ └───────┬────────┘└─┬┘└────┬────┘└─────┬──────┘└───┬───┘schema värd port sökväg querysträng fragment| Del | Betydelse |
|---|---|
| Schema | Protokollet, http eller https |
| Värd | Domännamnet eller IP-adressen till servern |
| Port | Utelämnas oftast. Standard är 80 för http och 443 för https. |
| Sökväg | Vilken resurs på servern som efterfrågas |
| Querysträng | Parametrar som namn=värde, åtskilda med & |
| Fragment | En plats på sidan. Skickas aldrig till servern, utan används bara av webbläsaren. |
Förfrågan och svar
Section titled “Förfrågan och svar”HTTP/1.1 är text. En förfrågan består av en förfrågningsrad, headers, en tom rad och ibland en body:
POST /login HTTP/1.1Host: example.comUser-Agent: Mozilla/5.0 ...Content-Type: application/x-www-form-urlencodedContent-Length: 27
username=ada&password=hemligtSvaret har samma form, men börjar med en statusrad:
HTTP/1.1 302 FoundLocation: /dashboardSet-Cookie: session=4f2a9c...; HttpOnly; Secure; SameSite=LaxContent-Length: 0HTTP/2 och HTTP/3 skickar samma information, men binärt och effektivare. Metoder, statuskoder och headers betyder samma sak i alla versioner.
Metoder
Section titled “Metoder”Metoden anger vad klienten vill göra med resursen.
| Metod | Används till | Säker | Idempotent |
|---|---|---|---|
GET |
Hämta en resurs | Ja | Ja |
HEAD |
Som GET, men bara headers |
Ja | Ja |
POST |
Skicka data, till exempel skapa något eller logga in | Nej | Nej |
PUT |
Ersätta en resurs helt | Nej | Ja |
PATCH |
Ändra delar av en resurs | Nej | Nej |
DELETE |
Ta bort en resurs | Nej | Ja |
OPTIONS |
Fråga vilka metoder som är tillåtna, används av webbläsaren för CORS | Ja | Ja |
Säker betyder att metoden inte ändrar något på servern. En GET får därför aldrig ta bort eller
ändra data. Idempotent betyder att samma förfrågan gjord flera gånger ger samma resultat som en
gång. Två DELETE av samma resurs lämnar den borttagen, medan två POST kan skapa två resurser.
Statuskoder
Section titled “Statuskoder”Statuskoden är ett tresiffrigt tal där första siffran anger vilken sorts svar det är:
| Klass | Betydelse |
|---|---|
1xx |
Information. Den du möter är 101 Switching Protocols, när en anslutning byter från HTTP till WebSocket. |
2xx |
Det gick bra |
3xx |
Omdirigering: resursen finns någon annanstans |
4xx |
Klienten gjorde fel |
5xx |
Servern gjorde fel |
De du oftast möter:
| Kod | Betydelse |
|---|---|
200 OK |
Allt gick bra |
201 Created |
En ny resurs skapades |
204 No Content |
Det gick bra, men svaret har ingen body |
301 Moved Permanently |
Resursen har flyttat för gott. Den nya adressen står i Location. |
302 Found och 303 See Other |
Gå till adressen i Location, till exempel efter ett formulär |
304 Not Modified |
Din cachade kopia gäller fortfarande |
400 Bad Request |
Förfrågan är felaktig |
401 Unauthorized |
Du behöver logga in |
403 Forbidden |
Du är inloggad, men har inte behörighet |
404 Not Found |
Resursen finns inte |
405 Method Not Allowed |
Resursen finns, men inte med den metoden |
500 Internal Server Error |
Något gick fel i servern, ofta ett fel i koden |
502 Bad Gateway och 503 Service Unavailable |
Servern bakom en proxy svarar inte, eller är överbelastad |
Headers
Section titled “Headers”Headers är metadata om förfrågan och svaret, i formen Namn: värde. Några av de vanligaste:
| Header | Finns i | Betydelse |
|---|---|---|
Host |
Förfrågan | Vilken webbplats förfrågan gäller. Krävs, eftersom många webbplatser kan dela IP-adress. |
User-Agent |
Förfrågan | Vilket program som skickar förfrågan |
Accept |
Förfrågan | Vilka format klienten förstår, till exempel text/html eller application/json |
Content-Type |
Båda | Formatet på bodyn |
Content-Length |
Båda | Bodyns storlek i byte |
Location |
Svar | Adressen att gå vidare till vid en omdirigering |
Cache-Control |
Båda | Om och hur länge svaret får cachas |
Set-Cookie |
Svar | Ber klienten spara en cookie |
Cookie |
Förfrågan | Skickar med klientens sparade cookies |
Authorization |
Förfrågan | Inloggningsuppgifter, till exempel en token |
Skicka data till servern
Section titled “Skicka data till servern”Data skickas i querysträngen eller i bodyn. Content-Type talar om hur bodyn är formaterad:
Content-Type |
Exempel | Används av |
|---|---|---|
application/x-www-form-urlencoded |
namn=Ada&sprak=JavaScript |
Vanliga HTML-formulär |
multipart/form-data |
Delar åtskilda av en gränssträng | Formulär som laddar upp filer |
application/json |
{"namn":"Ada"} |
API:er och fetch från JavaScript |
Querysträngen syns i adressfältet, i webbläsarens historik och i serverns loggar. Känslig data som
lösenord skickas därför alltid i bodyn, med POST.
Cookies
Section titled “Cookies”En cookie är ett litet namngivet värde som servern ber webbläsaren spara med headern Set-Cookie.
Webbläsaren skickar sedan tillbaka det i headern Cookie i varje förfrågan till samma webbplats. Så
kan en tillståndslös server ändå känna igen en användare: vid inloggningen skapar servern en
session, sparar vem användaren är och skickar ett slumpmässigt sessions-id i en cookie.
Set-Cookie: session=4f2a9c...; HttpOnly; Secure; SameSite=Lax; Max-Age=3600| Attribut | Betydelse |
|---|---|
HttpOnly |
JavaScript på sidan kan inte läsa cookien, vilket skyddar mot stöld via XSS |
Secure |
Cookien skickas bara över HTTPS |
SameSite |
Om cookien skickas med förfrågningar från andra webbplatser, vilket skyddar mot CSRF |
Max-Age eller Expires |
Hur länge cookien lever. Utan dem försvinner den när webbläsaren stängs. |
Sessioner, XSS och CSRF återkommer i kursen, bland annat i vecka 5 om webbsäkerhet.
HTTPS och certifikat
Section titled “HTTPS och certifikat”HTTPS är HTTP inuti en krypterad TLS-anslutning. Krypteringen gör att ingen på vägen kan läsa eller ändra det som skickas, till exempel lösenord och cookies. Men kryptering hjälper inte om du pratar med fel server. Därför visar servern upp ett certifikat, som:
- innehåller serverns domännamn och dess publika nyckel
- är signerat av en certifikatutfärdare (certificate authority, CA) som webbläsaren litar på
- gäller en begränsad tid, ofta några månader
Webbläsaren kontrollerar att certifikatet gäller för rätt domän, att det inte har gått ut och att signaturen leder till en betrodd CA. Serverns privata nyckel får aldrig lämna servern. Den som har den kan utge sig för att vara servern. Du sätter upp certifikat för din egen server senare i kursen.
Verktyg
Section titled “Verktyg”Webbläsarens utvecklarverktyg (F12, eller Cmd+Option+I på macOS) har fliken Network (Nätverk), som visar varje förfrågan en sida gör, med metod, status, headers, body och tid.
curl gör HTTP-förfrågningar från terminalen:
| Kommando | Vad det gör |
|---|---|
curl <url> |
Hämtar och skriver ut bodyn |
curl -i <url> |
Visar också svarets headers |
curl -I <url> |
Gör en HEAD-förfrågan och visar bara headers |
curl -v <url> |
Visar allt: förfrågan (>), svar (<) och anslutningen (*) |
curl -L <url> |
Följer omdirigeringar |
curl -d 'a=1&b=2' <url> |
Skickar ett formulär med POST |
curl -X DELETE <url> |
Använder en annan metod |
curl -H 'Accept: application/json' <url> |
Lägger till en header |
curl -c fil -b fil <url> |
Sparar och skickar cookies i en fil, som en webbläsare |
Övningar
Section titled “Övningar”Tidsåtgång: Ungefär en och en halv timme för alla nio övningarna.
När du har gått igenom sidan kan du pröva dina kunskaper med övningarna nedan. Gör dem i ordning, eftersom flera bygger på varandra. Försök själv innan du tittar på lösningsförslaget.
1. Titta på trafiken
Section titled “1. Titta på trafiken”Tidsåtgång: Ungefär 10 minuter.
Öppna utvecklarverktygen, välj fliken Network och ladda om
kursens startsida. Hur många
förfrågningar gör sidan? Vilken Content-Type har sidan själv, och vilken har en CSS-fil? Högerklicka
på kolumnrubrikerna och slå på kolumnen Protocol. Vilken HTTP-version används? Jämför med
www.google.com.
Lösningsförslag
Section titled “Lösningsförslag”Sidan gör många förfrågningar: först själva HTML-sidan och sedan CSS, JavaScript, typsnitt och
bilder som HTML-sidan hänvisar till. HTML-sidan har text/html och CSS-filerna text/css.
Kurswebbplatsen svarar med http/1.1, medan Google använder h2 (HTTP/2) eller h3 (HTTP/3). Med
HTTP/2 och 3 kan många förfrågningar dela en enda anslutning, vilket gör sidor med många resurser
snabbare.
2. En förfrågan i detalj
Section titled “2. En förfrågan i detalj”Tidsåtgång: Ungefär 5 minuter.
Hämta kursens startsida med curl -v. Vilka rader är förfrågan och vilka är svaret? Vilka headers
skickade curl utan att du bad om det?
curl -v https://coursepress.lnu.se/kurser/webbprogrammering-pa-serversidan/Lösningsförslag
Section titled “Lösningsförslag”Rader som börjar med > är förfrågan, rader med < är svaret och rader med * beskriver
anslutningen, till exempel TLS. curl skickar själv Host, User-Agent och Accept. Host
krävs, eftersom många webbplatser kan dela samma IP-adress.
3. Omdirigeringar
Section titled “3. Omdirigeringar”Tidsåtgång: Ungefär 5 minuter.
Gör en HEAD-förfrågan till http://coursepress.lnu.se (utan s). Vilken statuskod får du, och
vart skickas du? Följ omdirigeringarna till slutet.
Lösningsförslag
Section titled “Lösningsförslag”curl -I http://coursepress.lnu.securl -IL http://coursepress.lnu.seServern svarar 301 Moved Permanently med Location: https://coursepress.lnu.se/. All trafik
flyttas till HTTPS. Med -L följer curl efter, precis som webbläsaren gör automatiskt.
4. HTTP för hand
Section titled “4. HTTP för hand”Tidsåtgång: Ungefär 10 minuter.
HTTP/1.1 är text som skickas över en TCP-anslutning. Skapa filen raw-http.mjs, som öppnar en
TCP-anslutning till port 80 och skriver en förfrågan för hand. Kör den med node raw-http.mjs.
Vad händer om du tar bort raden med Host?
import { connect } from 'node:net'
const host = 'coursepress.lnu.se'
const socket = connect(80, host, () => { socket.write( 'GET /kurser/webbprogrammering-pa-serversidan/ HTTP/1.1\r\n' + `Host: ${host}\r\n` + 'Connection: close\r\n' + '\r\n' )})
socket.setEncoding('utf8')socket.on('data', (chunk) => process.stdout.write(chunk))Lösningsförslag
Section titled “Lösningsförslag”Svaret är ren text: statusraden HTTP/1.1 301 Moved Permanently, headers, en tom rad och en kort
HTML-body. Det är samma svar som i övning 3.
Utan Host svarar servern 400 Bad Request, eftersom HTTP/1.1 kräver headern. \r\n är
radslutet som HTTP föreskriver, och den tomma raden sist talar om att förfrågans headers är slut.
Connection: close ber servern stänga anslutningen efter svaret, så att programmet avslutas.
5. En egen server
Section titled “5. En egen server”Tidsåtgång: Ungefär 10 minuter.
Skapa filen server.mjs med koden nedan och starta den med node server.mjs. Öppna
localhost:3000 i webbläsaren och hämta samma adress med curl. Jämför vad
servern skriver ut för de två förfrågningarna. Vilka headers skiljer sig åt?
import { createServer } from 'node:http'
const server = createServer((req, res) => { console.log(req.method, req.url, req.headers)
let body = '' req.on('data', (chunk) => { body += chunk }) req.on('end', () => { if (body) console.log('Body:', body)
if (req.url !== '/') { res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' }) res.end('Hittades inte\n') return }
// The server remembers nothing between requests; the cookie carries the count. const visits = Number(req.headers.cookie?.match(/visits=(\d+)/)?.[1] ?? 0) + 1
res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8', 'Set-Cookie': `visits=${visits}; HttpOnly; SameSite=Lax` }) res.end(`Hej! Det här är besök nummer ${visits}.\n`) })})
server.listen(3000, '127.0.0.1', () => { console.log('Lyssnar på http://localhost:3000')})Lösningsförslag
Section titled “Lösningsförslag”Webbläsaren skickar många fler headers än curl: en längre User-Agent, en Accept som föredrar
text/html, Accept-Language med dina språkinställningar, Accept-Encoding för komprimering och
ofta Sec-Fetch-*-headers som beskriver vad förfrågan gäller. Webbläsaren gör också ofta en extra
förfrågan till /favicon.ico, som får 404.
6. Tillståndslöst
Section titled “6. Tillståndslöst”Tidsåtgång: Ungefär 10 minuter.
Ladda om sidan i webbläsaren några gånger. Räknaren ökar. Hämta sedan sidan med curl två gånger.
Varför står det alltid besök nummer 1? Få curl att räkna uppåt, som webbläsaren. Var hittar du
cookien i utvecklarverktygen?
Lösningsförslag
Section titled “Lösningsförslag”curl http://localhost:3000curl http://localhost:3000curl -c kakor.txt -b kakor.txt http://localhost:3000curl -c kakor.txt -b kakor.txt http://localhost:3000Servern minns ingenting. Den läser räknaren från cookien i förfrågan och skickar tillbaka ett nytt
värde i Set-Cookie. Webbläsaren sparar cookien och skickar den med nästa gång, men curl gör det
bara om du ber den med -c (spara) och -b (skicka).
I Chrome och Edge finns cookien under fliken Application, i Firefox under Storage. Att den är
HttpOnly betyder att document.cookie i konsolen inte visar den. Pröva!
7. Skicka data
Section titled “7. Skicka data”Tidsåtgång: Ungefär 10 minuter.
Skicka ett formulär med namn=Ada&sprak=JavaScript till servern med curl. Vilken metod och vilken
Content-Type använde curl, och hur ser bodyn ut i serverns utskrift? Skicka sedan en
DELETE-förfrågan till / och till /finns-inte. Vilka statuskoder får du?
Lösningsförslag
Section titled “Lösningsförslag”curl -d 'namn=Ada&sprak=JavaScript' http://localhost:3000curl -i -X DELETE http://localhost:3000curl -i -X DELETE http://localhost:3000/finns-inte-d gör att curl använder POST med Content-Type: application/x-www-form-urlencoded, precis
som ett HTML-formulär. Bodyn kommer fram som texten namn=Ada&sprak=JavaScript.
DELETE / ger 200, eftersom servern inte bryr sig om metoden, medan /finns-inte ger 404.
8. Rätt statuskod
Section titled “8. Rätt statuskod”Tidsåtgång: Ungefär 15 minuter.
Servern i övning 7 svarar 200 på DELETE /, fast den inte kan ta bort något. Ändra servern så att
den svarar 405 Method Not Allowed på alla metoder utom GET och POST. Svaret ska ha headern
Allow, som talar om vilka metoder som är tillåtna. Kontrollera med curl -i.
Lösningsförslag
Section titled “Lösningsförslag”Lägg till kontrollen efter den som ger 404:
if (req.method !== 'GET' && req.method !== 'POST') { res.writeHead(405, { 'Content-Type': 'text/plain; charset=utf-8', Allow: 'GET, POST' }) res.end('Metoden stöds inte\n') return}curl -i -X DELETE http://localhost:3000# HTTP/1.1 405 Method Not Allowed# Allow: GET, POSTOrdningen spelar roll: först avgörs om resursen finns (404), sedan om metoden är tillåten för den
(405). Rätt statuskoder gör att klienter, verktyg och andra utvecklare förstår vad som hände utan
att läsa texten i svaret. I kursens ramverk, Express, sköts mycket av det här åt dig, men det är
samma HTTP under ytan.
9. Certifikatet
Section titled “9. Certifikatet”Tidsåtgång: Ungefär 5 minuter.
Klicka på ikonen till vänster om adressen i webbläsaren när du är på kurswebbplatsen och öppna certifikatet. För vilket domännamn gäller det, vem har utfärdat det och när går det ut?
Lösningsförslag
Section titled “Lösningsförslag”Certifikatet gäller coursepress.lnu.se, eller flera namn inklusive det. Utfärdaren är en CA som
webbläsaren litar på, och certifikatkedjan visar hela vägen upp till en rotutfärdare som finns
inbyggd i webbläsaren eller operativsystemet. Certifikat gäller numera sällan längre än ett år, och
förnyas därför automatiskt på de flesta servrar.
Fördjupning
Section titled “Fördjupning”- An overview of HTTP och resten av MDN:s guider om HTTP, en av kursens rekommenderade lärresurser
- How the web works på MDN, en kort översikt över hela kedjan
- How HTTPS works, en tecknad förklaring av TLS och certifikat
- High Performance Browser Networking av Ilya Grigorik, med kapitel om HTTP/1.1, HTTP/2 och TLS
- RFC 9110: HTTP Semantics, standarden som definierar metoder, statuskoder och headers
Kursens inspelning om HTTP från 2021 finns kvar i tidigare kursomgångar.