CORS-fejl i browseren
Find den rigtige årsag bag en CORS-fejl mod api.danadresse.dk, som er åbent for alle domæner, og ret credentials, mixed content, proxyer og nøgletype.
API'et tillader kald fra alle domæner. Får du alligevel en CORS-fejl i browserkonsollen, er årsagen næsten altid en anden end en manglende CORS-tilladelse: et kald med cookies, en http://-adresse, et kald, der aldrig nåede frem til API'et (et netværksproblem, en firewall, en browserudvidelse), eller en proxy, der ændrer headerne. Denne guide går årsagerne igennem i den rækkefølge, de typisk opstår.
Hvad API'et sender
Alle svar fra API'et har Access-Control-Allow-Origin: *, også fejlene: 400, 401, 403 (også fra misbrugsfilteret), 404, 429, 500 og 503. Svar på et kald med en Origin-header lister også de headere, din kode må læse:
| Header | Værdi |
|---|---|
Access-Control-Allow-Origin | * |
Access-Control-Expose-Headers | X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-RateLimit-Minute-Limit, X-RateLimit-Minute-Remaining, X-RateLimit-Minute-Reset, Retry-After, X-Quota-Grace, X-Quota-Remaining, ETag |
Et preflight (OPTIONS) besvares med Access-Control-Allow-Methods: GET, POST, OPTIONS, de headere du beder om (fx x-api-key og content-type), og Access-Control-Max-Age: 86400. Preflight kræver ingen nøgle og tæller ikke som et kald.
Se det selv. Det første kald er et almindeligt GET med en Origin-header, det andet et preflight:
curl -s -D - -o /dev/null "https://api.danadresse.dk/postnumre/8000" \ -H "Origin: https://shop.example.dk" \ -H "X-Api-Key: $DANADRESSE_API_KEY" | tr 'A-Z' 'a-z' | grep '^access-control' curl -s -D - -o /dev/null -X OPTIONS "https://api.danadresse.dk/postnumre/8000" \ -H "Origin: https://shop.example.dk" \ -H "Access-Control-Request-Method: GET" \ -H "Access-Control-Request-Headers: x-api-key" | tr 'A-Z' 'a-z' | grep '^access-control'
Start i netværksfanen
Åbn udviklerværktøjernes netværksfane og find kaldet:
- En status som 400, 401, 403, 404, 429 eller 500 er synlig. Så er det ikke et CORS-problem. Klik på kaldet og læs svaret. Se Fejlformatet.
- Status 410 fra
dawa.aws.dkellerapi.dataforsyningen.dk. Koden kalder stadig DAWA, som lukkede 1. oktober 2026. Søg hele kodebasen igennem, også bundlede filer og CMS-indstillinger, og skift tilhttps://api.danadresse.dk. Se Skift fra DAWA. - Kaldet står som
(failed),CORS errorellerNS_ERROR_…uden status. Så nåede svaret ikke frem med CORS-headere. Gå tjeklisten igennem.
Tjeklisten
1. Kaldet sender cookies (credentials).
- Symptom: Konsollen skriver noget i retning af
The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. - Årsag:
fetch(url, { credentials: "include" }),axiosmedwithCredentials: trueeller jQuery medxhrFields: { withCredentials: true }. Browsere afviser*sammen med credentials, og API'et bruger ikke cookies. - Løsning: Fjern credentials fra kaldet. Nøglen skal i
X-Api-Keyellerapi_key.
const API_KEY = "DIN_BROWSER_NØGLE"; // låst til dit domæne // Forkert: credentials: "include" giver en CORS-fejl // Rigtigt: const res = await fetch("https://api.danadresse.dk/autocomplete?q=Vesterbrogade", { headers: { "X-Api-Key": API_KEY }, });
2. Mixed content: http:// fra en https://-side.
- Symptom: Konsollen skriver
Mixed Content, eller netværksfanen viserblocked:mixed-content. - Årsag: API-adressen i koden starter med
http://. Browseren blokerer kaldet, før det bliver sendt. - Løsning: Brug
https://api.danadresse.dk.
3. Kaldet nåede aldrig frem til API'et.
- Årsag: Alle svar fra selve API'et har CORS-headere, også fejlene. En CORS-fejl uden status betyder derfor som regel, at svaret kom et andet sted fra, eller slet ikke kom:
- en annonceblokker eller privatlivsudvidelse i browseren, der blokerer
api.danadresse.dk - en firmafirewall, proxy eller et VPN, der afbryder eller ændrer kaldet
- en 502 eller 504 fra proxyen foran API'et, fx ved en timeout eller under en udrulning
- en tabt forbindelse (offline, DNS)
- en annonceblokker eller privatlivsudvidelse i browseren, der blokerer
- Løsning: Prøv et privat vindue uden udvidelser, og kør derefter det samme kald med curl fra samme netværk. Får curl et svar med
access-control-allow-origin, ligger problemet i browseren eller netværket. Får du 502 eller 504, så se Fejl 503 og timeouts.
4. Din egen proxy ændrer headerne.
- Symptom: Konsollen skriver
The 'Access-Control-Allow-Origin' header contains multiple values '*, *'. - Årsag: Du kalder API'et gennem din egen server (nginx, en Next.js-route, en Cloudflare Worker), og proxyen både sender vores
Access-Control-Allow-Originvidere og tilføjer sin egen. - Løsning: Lad kun ét led sætte CORS-headere. Kalder din side din egen proxy på samme domæne, behøver du slet ingen CORS-headere. Se Next.js route handler som proxy.
// Next.js route handler: send kun body og content-type videre const upstream = await fetch(url, { headers: { "X-Api-Key": process.env.DANADRESSE_API_KEY } }); return new Response(upstream.body, { status: upstream.status, headers: { "content-type": upstream.headers.get("content-type") ?? "application/json" }, });
5. Gammel JSONP-kode.
- Sådan virker det:
$.ajax({ dataType: "jsonp" })og<script>-tags medcallback=virker på DAWA-stierne. Svaret pakkes ind somfn(…);medContent-Type: application/javascript, og JSONP kræver slet ikke CORS. Et script-tag kan ikke sende headere, så nøglen skal i URL'en somapi_key=. - Fejler det alligevel: callback-navnet skal være et almindeligt JavaScript-navn som
cbellerjQuery123_456(ellers får du almindelig JSON tilbage),/api/v1svarer ikke med JSONP, og en Content Security Policy på din side skal tilladehttps://api.danadresse.dkiscript-src. - Løsning: Brug
fetchi ny kode. Se Formater.
Ting, der ligner CORS-fejl, men ikke er det
En header er null i JavaScript. Browseren lader koden læse headerne i Access-Control-Expose-Headers (se tabellen ovenfor) og de standardheadere, der altid er tilladt. Så res.headers.get("Retry-After") og headerne X-RateLimit-* og X-Quota-* virker i browseren. Andre headere, fx X-Danadresse-Key-Status, bliver sendt, men giver null i browserkode. Læs dem på serveren.
403 origin_not_allowed. Nøglen er låst til domæner, og siden står ikke på listen. Svaret har CORS-headere og en læsbar body. Se Fejl 403.
Servernøglen virker i browseren. En nøgle uden domænelås virker fra enhver side, fordi CORS er åbent. Det er ikke en sikkerhedsgrænse: enhver kan kopiere nøglen fra sidens kildekode. Brug en browsernøgle med Tilladte domæner i frontend-kode, og hold servernøglen på serveren. Se Browsernøgler og tilladte domæner.
Næste skridt
Relaterede guides
Markdown-kilde Fejl i guiden? Skriv til os API-reference (Swagger)