‘Blocked by CORS policy: No Access-Control-Allow-Origin header’? Lees waarom de browser dit blokkeert en hoe je CORS goed instelt in nginx, PHP of Express.
Browsers volgen de same-origin policy: JavaScript op de ene ‘origin’ mag niet zomaar antwoorden lezen van een andere. Een origin is de combinatie van protocol, domein en poort. https://www.voorbeeld.nl, https://api.voorbeeld.nl en http://localhost:3000 zijn dus drie verschillende origins. Wil een pagina via fetch of XMLHttpRequest gegevens van een andere origin ophalen, dan moet die andere server expliciet toestemming geven. Dat mechanisme heet CORS (Cross-Origin Resource Sharing).
Die toestemming gaat via HTTP-headers in het antwoord van de server, vooral Access-Control-Allow-Origin. Ontbreekt die header, of staat er een andere origin in, dan krijgt jouw JavaScript het antwoord niet te zien en toont de console de fout. Belangrijk: het verzoek kan op de server wél zijn uitgevoerd; de browser houdt alleen het antwoord tegen.
Daarom is dit geen browserbug, en ook niet iets wat je in de JavaScript-code van de pagina kunt oplossen. De server van de API bepaalt wie zijn antwoorden mag lezen. De oplossing hoort dus aan de serverkant, of je laat de aanvraag via je eigen server lopen. Een veelvoorkomende variant: de echte fout is een 404 of 500 van de API, en omdat die foutpagina geen CORS-headers heeft, zie je alleen de CORS-melding.
curl werkt wel; alleen het ophalen vanuit JavaScript op een andere origin faalt.Menunamen kunnen per versie of toestel iets anders heten. Loop de stappen op volgorde af en stop zodra het werkt.
Open de ontwikkelaarstools, ga naar Network en klik op het mislukte verzoek. Kijk naar de statuscode en de antwoordheaders. Is de status 404, 500 of 401, los dan eerst die fout op; de CORS-melding is dan een gevolg. Staat er een apart OPTIONS-verzoek, dan gaat het om de preflight.
Bij verzoeken die verder gaan dan een eenvoudige GET of formulier-POST, bijvoorbeeld met Content-Type: application/json, een Authorization-header of de methode PUT of DELETE, stuurt de browser eerst een OPTIONS-verzoek. De server moet daarop antwoorden met een geslaagde status (zoals 204) en de headers Access-Control-Allow-Origin, Access-Control-Allow-Methods en Access-Control-Allow-Headers. Pas daarna volgt het echte verzoek.
Geef alleen origins toestemming die je vertrouwt. Gebruik always, zodat de headers ook bij foutantwoorden worden meegestuurd. Let op: zet je ergens in een location een eigen add_header, dan worden headers van een hoger niveau daar niet meer overgenomen. Test daarna met nginx -t en herlaad.
location /api/ {
add_header 'Access-Control-Allow-Origin' 'https://www.voorbeeld.nl' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization' always;
add_header 'Vary' 'Origin' always;
if ($request_method = 'OPTIONS') {
return 204;
}
# ... rest van de configuratie (proxy_pass, try_files)
}Werk je zonder toegang tot de webserver, zet de headers dan bovenaan het PHP-script, vóór enige uitvoer (anders krijg je headers already sent). Controleer de meegestuurde origin tegen een lijst en beantwoord een OPTIONS-verzoek direct.
<?php
$toegestaan = ['https://www.voorbeeld.nl', 'http://localhost:3000'];
$origin = $_SERVER['HTTP_ORIGIN'] ?? '';
if (in_array($origin, $toegestaan, true)) {
header('Access-Control-Allow-Origin: ' . $origin);
header('Vary: Origin');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
}
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
http_response_code(204);
exit;
}Voor Express is er het npm-pakket cors. Geef de toegestane origin op in plaats van alles open te zetten. Het pakket beantwoordt ook de preflight.
npm install cors
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: ['https://www.voorbeeld.nl'],
credentials: true
}));Stuur je cookies of inloggegevens mee (fetch(url, { credentials: 'include' }) of withCredentials), dan mag Access-Control-Allow-Origin geen * zijn. De server moet dan de exacte origin terugsturen én Access-Control-Allow-Credentials: true. Cookies moeten daarnaast zelf geschikt zijn voor gebruik tussen sites (SameSite=None; Secure).
Is de API van een ander en geeft die geen CORS-toestemming, dan kun je dat niet vanuit de browser omzeilen. Laat je eigen server de API aanroepen en het resultaat doorgeven aan je pagina, of stel tijdens ontwikkeling een proxy in je ontwikkelserver in. Plugins die CORS in je eigen browser uitschakelen helpen alleen jou, niet je bezoekers, en maken je browser onveiliger.
Let op: Zet niet uit gemak Access-Control-Allow-Origin: * op een API die met cookies of inloggegevens werkt. Kopieer ook nooit blind de Origin-header terug zonder lijst: dan geeft je server elke website toestemming om namens ingelogde bezoekers gegevens te lezen.
Zonder same-origin policy zou elke website die je bezoekt via jouw browser verzoeken kunnen doen naar andere sites waar je bent ingelogd, zoals je webmail of internetbankieren, en de antwoorden kunnen uitlezen. CORS is de gecontroleerde uitzondering daarop: alleen de server die de gegevens heeft, mag bepalen welke andere sites ze mogen lezen.
curl of Postman hebben geen same-origin policy en tonen daarom geen CORS-fout.Kom je er met deze stappen niet uit, of wil je het liever niet zelf doen? We kijken online mee of komen langs. Hulp op afstand kost €20 per uur; komen we langs, dan is de prijs op aanvraag. Je weet vooraf waar je aan toe bent.
Schrijf kort wat er misgaat en wat je al hebt geprobeerd. Kies of we bellen, online meekijken of langskomen.
Nee. Opties als mode: 'no-cors' zorgen alleen dat je een leeg, onleesbaar antwoord krijgt. De server moet de toestemming geven, of je laat je eigen server het verzoek doen.
Die tools hebben geen same-origin policy. Alleen browsers handhaven CORS, omdat zij de cookies en sessies van de gebruiker bewaren.
Voor openbare gegevens zonder inloggen kan dat. Werk je met cookies of inloggegevens, dan staat de browser dat niet toe en moet je de exacte origin opgeven.
Vaak geeft de API een fout (bijvoorbeeld 500 of 502) en heeft die foutpagina geen CORS-headers. Kijk in het tabblad Network naar de echte statuscode.
Hulp nodig van een mens? Website-onderhoud · Hosting en onderhoud · WordPress-support · Alle oplossingen