Forhandling af HTTP-indhold passer til Serverens svar Formatet i hostingen tilpasser sig automatisk kundens krav og evaluerer headere som Accept, Accept-Language og Accept-Encoding. Afhængigt af headeren leverer jeg den bedste variant - såsom JSON i stedet for XML, Gzip eller Brotli og det korrekte sprog - og styrker dermed weboptimering Bemærkelsesværdigt.
Centrale punkter
Følgende nøglepunkter giver et hurtigt overblik, før jeg forklarer implementeringen trin for trin.
- Overskrift kontrolformat, sprog, tegnsæt og komprimering.
- Server-drevet Forhandling forkorter rundturen og fremskynder leveringen.
- Vary-header forhindrer cache-forvirring og holder varianter rent adskilt.
- Tilbagefald med JSON/HTML og status 406 sikrer forudsigelig adfærd.
- q-værdier kontrolprioriteter, hvis flere varianter er mulige.
Hvad er HTTP-indholdsforhandling i hosting?
Jeg bruger Forhandling af indhold, for at levere en ressource i den bedst mulige variant uden at bygge flere endpoints. Klienten sender præferencer i overskrifterne Accept, Accept-Language, Accept-Charset og Accept-Encoding, og jeg svarer med de relevante Serverens svar format. For eksempel modtager en browser HTML, en bot JSON og en billedklient WebP eller AVIF. I hosting-opsætninger dominerer den serverdrevne forhandling, fordi den ikke udløser yderligere round trips og svarer direkte på headerne. Hvis der ikke er nogen passende variant tilbage, svarer jeg konsekvent med 406 Not Acceptable, så klienterne får et klart signal.
Overblik over forespørgsels- og svarhoveder
Ved pålidelige forhandlinger er jeg altid opmærksom på to sider: Den indkommende Anmodning om header med præferencer og de udgående svarhoveder med unik mærkning. Accept viser tilladte medietyper, Accept-Language foretrukne sprog, Accept-Charset tegnsættet og Accept-Encoding mulige komprimeringer. Jeg sætter svaret op med Content-Type, Content-Language, Content-Encoding og den korrekte Vary-header, så cacher ikke serverer forkerte varianter. Vary-headeren fortæller caches, hvilke egenskaber de skal bruge til at skelne mellem varianter, såsom Vary: Accept, Accept-Language. Hvis du bruger content negotiation http, skal du opretholde denne header-kombination konsekvent, ellers vil der opstå fejl i cachen.
| Overskrift | Formål | Eksempel | Vigtigt svar | Hint til cachen |
|---|---|---|---|---|
| Accepter | Tilladte medietyper | application/json; q=0.9, text/html; q=0.8 | Indholdstype: application/json | Variabel: Accept |
| Accept-sprog | Foretrukne sprog | de-DE, en-US; q=0,7 | Indholdssprog: de-DE | Vary: Accept-Language |
| Accepter charset | Tegnsæt | utf-8 | Content-Type: text/html; charset=utf-8 | Vary: Accept charset |
| Accept-Encoding | Kompression | br, gzip; q=0.8 | Indholdskodning: br | Vary: Accept-kodning |
Server-drevet, klient-drevet og request-drevet
Jeg skelner mellem tre tilgange og vælger, afhængigt af projektet, den passende Model. Serverdrevet (proaktiv) er min standard, da serveren beslutter sig direkte ud fra overskrifterne og straks returnerer en variant. Klientdrevet (reaktiv) lader klienten vælge fra en liste, men genererer ekstra arbejde på grund af yderligere anmodninger. Request-driven blander begge dele, f.eks. ved at tælle parametre i URL'en sammen med Accept-headers. I hostingmiljøer med høj belastning er serverdrevet adfærd overbevisende, fordi det sparer round trips, aflaster cacher og giver mulighed for klare regler.
Apache: .htaccess, MultiViews og typekort
På Apache aktiverer jeg MultiViews eller bruge typekort til automatisk at servere sprog- og formatvarianter. MultiViews tillader filpar som index.html.de og index.html.en, som Apache vælger ud fra Accept-Language. Jeg indstiller q-værdier for medietyper, så moderne formater prioriteres, f.eks. image/webp før image/jpeg. Jeg sørger altid for at indstille Vary korrekt og levere 406, hvis klienter anmoder om et ikke-understøttet format. Det gør adfærden forudsigelig og forhindrer, at cachen gemmer modstridende svar.
# .htaccess
Indstillinger +MultiViews
# Eksempel på Type-Map (file.var)
URI: billede
Indholdstype: image/webp; qs=0.9
Indholdstype: image/jpeg; qs=0.8
Indholdssprog: de
# betjener automatisk sprogvarianten
#-filer: index.html.de, index.html.en
Nginx: map, Lua og kantlogik
Under Nginx sætter jeg ofte kort-direktiver til at evaluere Accept-headere og tildele passende slutpunkter. For API'er omdirigerer jeg mellem HTML og JSON afhængigt af Accept, eventuelt suppleret med Lua for finere regler. Jeg holder øje med Vary-headeren, fordi cacher skal linke beslutninger til Accept og Accept-Language. I distribuerede opsætninger flytter jeg dele af forhandlingen til edge nodes for at minimere ventetiden. En hvidliste er stadig vigtig, så jeg kun tilbyder verificerede medietyper og ikke falder for eksotiske formater.
# nginx.conf (uddrag)
map $http_accept $fmt {
standard "html";
"~*application/json" "json";
"~*\\*/\\*" "json";
}
server {
add_header Vary "Accept, Accept-Language";
placering /api {
try_files $uri $uri/ /api.$fmt;
}
}
Caching, Vary og SEO-signaler
Uden korrekt Varierer-headers, opfører cachen sig uforudsigeligt og leverer forkerte varianter til andre brugere. Jeg sætter Vary præcis til de overskrifter, som jeg bruger til at differentiere, dvs. typisk Accept, Accept-Language og Accept-Encoding. Det styrker ikke kun konsistensen, men sender også klare signaler om performance, hvilket indirekte giver SEO-fordele. De, der ønsker at dykke dybere ned i header-strategier, vil få gavn af denne guide til HTTP-overskrifter til performance og SEO. Jeg tjekker også, om CDN-cachenøglen mapper disse dimensioner, så edge-noderne indeholder de rigtige objekter.
API'er: Whitelisting-formater og ren fallback
Med API'er opbevarer jeg de understøttede medietyper i en Whitelist for eksempel application/json og application/xml. Hvis Accept-headeren mangler, eller der ikke er noget, der passer, leverer jeg JSON som standard, da det er det mest understøttede. Hvis en klient udtrykkeligt anmoder om et ukendt format, svarer jeg med 406 Not Acceptable i stedet for at gætte i stilhed. En brugers profilindstillinger har forrang frem for Accept, hvis applikationen specificerer dette. Jeg sikrer, at disse regler er centraliserede, reproducerbare og validerede ved hjælp af tests, så integrationerne forbliver stabile.
Sprog, skrifttyper og tilgængelighed
For Flersprogethed Jeg bruger Accept-Language til automatisk at vælge sprogvarianter og markere Content-Language i svaret. Jeg formulerer fallbacks klart: Hvis det ønskede sprog ikke findes, bruger jeg et defineret standardsprog. Jeg bruger Accept-Charset til at sikre, at UTF-8 anvendes overalt, så specialtegn vises konsekvent. Skærmlæsere har også gavn af korrekte sprognavne i indholdssproget og lang-attributter i markup'en. Det holder leveringen inkluderende, gennemsigtig og teknisk ren.
Billeder, komprimering og medietyper
Når det gælder billeder, giver jeg moderne formater en Projektion og vær opmærksom på browsernes Accept-overskrifter. Hvis klienten understøtter AVIF eller WebP, foretrækker jeg at levere disse versioner, ellers vælger jeg JPEG eller PNG. Denne praktiske guide hjælper mig med at vælge mellem WebP og AVIF Sammenligning af WebP og AVIF. Jeg reducerer også datamængden betydeligt ved hjælp af acceptkodning med Brotli eller Gzip, ofte op til 50 % i praksis. Det sparer båndbredde, forkorter time-to-first-byte og stabiliserer den opfattede hastighed.
Mål, test, rul ud
Jeg måler effekten af forhandling løbende, ellers er der stadig potentiale. Ubrugt. Jeg bruger curl til at tjekke varianter, f.eks. curl -H „Accept: application/json“ eller curl -H „Accept-Language: de“. Jeg tjekker hitrater pr. variant i logfiler og sammenligner dem med CDN-statistikker. For kodningsstrategier og Brotli-karakterer sammenligner jeg resultatkurver, før jeg indstiller globale standarder. Denne guide til opsætning og tuning giver mig en kompakt introduktion til Konfigurer HTTP-komprimering, som jeg koordinerer sideløbende med forhandlingerne.
Fejlkoder og edge cases i praksis
Jeg skelner klart mellem 406 Not Acceptable og 415 Unsupported Media Type: Jeg indstiller 406, hvis Svar ikke er tilgængelig i en accepteret variant (Accept denied); jeg bruger 415, hvis Forespørgsel sender en ikke-understøttet medietype (indholdstype i anmodningens payload). I sjældne tilfælde giver 300 Multiple Choices mening, hvis jeg vil tilbyde klienten flere nøjagtigt matchende varianter - i praksis bruger jeg dog klare standardindstillinger i stedet for interaktivt valg i miljøer med høj belastning. Til caching svarer jeg fortsat med 304 Not Modified pr. variant; ETag og Last-Modified gælder altid variantspecifikt. Hvis Accept mangler helt, fortolker jeg det som „alt er tilladt“ og bruger den definerede standard (normalt JSON for API'er, HTML for hjemmesider). Hvis en klient sætter q=0 for en type, udelukker jeg eksplicit denne variant.
Sikkerhed: sniffing, hvidlister og input-hygiejne
Jeg lader ikke browseren „gætte“ indholdstypen, men ligger med konsekvent indholdstype og X-Content-Type-Options: nosniff rettet. I forhandlingslogikken accepterer jeg kun typer/sprog på hvidlisten og begrænser headerlængden, så usædvanligt lange lister over accepterede sprog ikke optager ressourcer. Til logs og metrikker rydder jeg op i header-værdier for at undgå injektionsrisici. Jeg er også opmærksom på databeskyttelse: Accept-sprog kan gøre det muligt at drage konklusioner om brugere; jeg gemmer kun så meget som nødvendigt og aggregerer til statistik. Med CORS lader jeg forhandlingen bestemme selv - jeg binder cross-origin-regler separat til Origin/Methods/Headers, ikke til Accept-varianter, så jeg ikke genererer utilsigtede autorisationer.
CDN, cachenøgler og ETags pr. variant
Med CDN'er definerer jeg bevidst cachenøglen til at være variabel. Ud over URL inkluderer dette Accept, Accept-Language og Accept-Encoding, præcis som jeg signalerer i Vary-headeren. Jeg indstiller mine egne ETags for hver variant (f.eks. hash med suffix „.json.de.br“) og sikrer, at betingede anmodninger fungerer korrekt. Til statiske aktiver arbejder jeg med prægenererede, komprimerede filer (br/gz), som CDN'et serverer 1:1. For at reducere belastningen af oprindelsen bruger jeg „collapsed forwarding“ eller „stale-while-revalidate“: Den første miss opdateres, alle andre modtager en frisk eller „stale acceptable“ variant. Jeg kombinerer kun range-anmodninger med komprimering, hvis serveren og CDN'et håndterer funktionen konsekvent; ellers deaktiverer jeg range for dynamisk komprimerede svar for at undgå fragmentering af varianterne.
q-værdier, jokertegn og matchningsalgoritme
Hvis der findes flere varianter, sorterer jeg efter q-værdier og præcision: eksakt type/subtype slår type/*, begge slår */*. Hvis q er den samme, vinder den mere specifikke variant. Hvis klienten ikke angiver en q-værdi, fortolker jeg den som 1,0. Med q=0 udelukker klienten udtrykkeligt en type. For billeder og dokumenter foretrækker jeg moderne formater med en lidt højere q, men tilbyder fallbacks, hvis klienten f.eks. ikke genkender AVIF.
# Pseudokode til accept-matchning
analyser acceptHeader i kandidater (type, undertype, q)
for variant i serverVariants:
score = 0
for cand i candidates:
hvis cand.type == variant.type og cand.subtype == variant.subtype:
score = max(score, 1000 * cand.q + 2) # præcis
elif cand.type == variant.type og cand.subtype == "*":
score = max(score, 1000 * cand.q + 1) # type/*
elif cand.type == "*" og cand.subtype == "*":
score = max(score, 1000 * cand.q) # */*
Tildel den bedste score
vælg variant med højeste score eller 406, hvis alle scorer 0
Jeg går frem på samme måde med Accept-Language: „de-CH“ prioriterer „de-CH“ frem for „de“, og først derefter falder valget på den globale standard. Jeg holder udvælgelsen deterministisk, så cacher gemmer pålidelige objekter.
Eksempler på rammeværk: Express/Node og Go
I applikationsframeworks indkapsler jeg reglerne i middleware, sætter Vary konsekvent og holder fallbacks centraliseret.
// Express/Node (vereinfacht)
const vary = require('vary');
function negotiate(req, res, next) {
vary(res, 'Accept, Accept-Language, Accept-Encoding');
const types = req.accepts(['json', 'html']);
const lang = req.acceptsLanguages(['de', 'en']) || 'de';
res.set('Content-Language', lang);
if (!types) return res.status(406).send('Not Acceptable');
if (types === 'json') {
res.type('application/json; charset=utf-8');
return res.json({ ok: true, lang });
}
res.type('text/html; charset=utf-8');
res.send(`<html lang="${lang}">OK</html>`);
}
app.get('/resource', negotiate);
// Gå net/http (forenklet)
func negotiateJSON(r *http.Request) bool {
a := r.Header.Get("Accept")
if a == "" || strings.Contains(a, "*/*") { return true }
if strings.Contains(strings.ToLower(a), "application/json") { return true }
return false
}
func handler(w http.ResponseWriter, r *http.Request) {
w.Header().Add("Vary", "Accept, Accept-Language, Accept-Encoding")
if !negotiateJSON(r) {
w.WriteHeader(http.StatusNotAcceptable)
w.Write([]byte("Ikke acceptabel"))
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
io.WriteString(w, `{"ok":true}`)
}
Det er vigtigt, at jeg aldrig stoler på User-Agent, men kun på eksplicitte Accept*-headere. Det gør adfærden reproducerbar og testbar.
Internationalisering i detaljer
Jeg opretter en klar fallback-kæde, f.eks. de-CH → de-DE → de → Default. Hvis der ikke findes en regionskode, nedbryder jeg den til basissproget. I svaret bruger jeg Content-Language til at angive præcis den valgte variant og undgå blandede former. Brugerpræferencer (som f.eks. kontolokalitet) har forrang for Accept-Language, men er også deterministisk kortlagt til sprog, som systemet rent faktisk leverer. Af hensyn til SEO og tilgængelighed sørger jeg for, at lang-attributterne i HTML og indholdssproget er konsistente; jeg forhindrer også omdirigeringssløjfer ved at træffe beslutningen på serversiden og instruere caches korrekt via Vary.
Ren kanonisering af anmodningsdrevne varianter
Hvis jeg kombinerer URL-parametre (f.eks. ?format=json) med Accept, skal siden have en klar kanonisering: Enten accepterer jeg parameteren som en hård standard og ignorerer Accept, eller også er parameteren bare et hint, der kan tilsidesættes af Accept. Jeg dokumenterer tydeligt reglen og indstiller konsistente headere i svaret, så caches ikke gemmer to forskellige repræsentationer af den samme URL uden en adskillende Vary-nøgle. For HTML-sider sikrer jeg også en unik kanonisk adresse pr. sprog-/formatvariant i systemet, så analyser og overvågning ikke tæller duplikater.
Finjuster og forproducer kompression
Ved dynamiske svar afvejer jeg CPU-omkostningerne ved komprimering mod netværksbesparelserne. Brotli på niveau 4-6 giver typisk et godt forhold; højere niveauer er især værdifulde for statiske aktiver, som jeg komprimerer på forhånd. Jeg har både br og gzip ved hånden til store filer, fordi ikke alle klienter understøtter Brotli. I praksis gemmer jeg precompilerne med filtypenavne (.br/.gz), lader serveren beslutte ud fra accept af kodning og filstørrelsestærskler og indstiller indholdskodningen korrekt. Vigtigt: Hver komprimeret variant får sin egen ETag; ellers vil betingede anmodninger levere forkerte 304-svar.
Observerbarhed, canary og rollback
Jeg indfører forhandlingsregler med funktionsflag, aktiverer dem trin for trin (f.eks. 5 %, 25 %, 100 %) og overvåger nøgletal for hver variant: fejlrate, latenstid, bytes out, cache hit rate, andel 406/415. Jeg noterer den valgte variant og de udløsende overskrifter (samlet) i logfilerne, så jeg hurtigt kan finde uoverensstemmelser. Til test bruger jeg syntetiske testere, der regelmæssigt kører kendte acceptkombinationer mod staging og produktion. I tilfælde af uregelmæssigheder ruller jeg specifikt varianter tilbage uden at stoppe hele systemet - f.eks. ved midlertidigt at deaktivere AVIF, tvinge JSON som standard eller reducere Vary-dimensionen, indtil cachen er genoprettet.
Resumé: Det rigtige svarformat betaler sig
Jeg leverer hurtigere, sparer Båndbredde og øge tilfredsheden, hvis jeg bruger indholdsforhandling konsekvent. Kombinationen af Accept-overskrifter, klare fallbacks, q-værdier og Vary sikrer stabile, reproducerbare svar. I praksis prioriterer jeg serverdrevne beslutninger, holder cacher variant-kompatible og tester alle regler med curl. API'er får en streng hvidliste, hjemmesider nyder godt af sprog- og billedvarianter samt moderne komprimering. På den måde opnår projektet målbare fordele med hensyn til ydeevne, tilgængelighed og vedligeholdelsesvenlighed - med en opsætning, som jeg kontrollerer målrettet og til enhver tid kan spore.


