Introduction : quand le navigateur dit « non », mais Postman dit « oui »
Imaginez la situation : vous écrivez du frontend en JavaScript, vous faites une requête fetch vers une API. En réponse, une erreur rouge dans la console :
L'accès à la ressource à l'adresse 'https://api.example.com/data' depuis l'origine 'http://localhost:3000' a été bloqué par la politique CORS : aucun en-tête 'Access-Control-Allow-Origin' n'est présent sur la ressource demandée.Vous vous prenez la tête, vous ouvrez Postman, vous collez la même URL, vous appuyez sur Envoyer — et oh miracle, les données arrivent ! Le serveur fonctionne ? Il fonctionne. Alors pourquoi le navigateur bloque-t-il la requête ?
Cette situation est un classique du développement web. Sur Stack Overflow, cette question a rassemblé des milliers de vues. Aujourd'hui, nous allons regarder sous le capot et comprendre pourquoi cela se produit, comment fonctionne CORS et comment le corriger. C'est parti !
Qu'est-ce que CORS et pourquoi est-il nécessaire ?
CORS (Cross-Origin Resource Sharing) est un mécanisme de sécurité du navigateur. Il interdit au JavaScript d'un site (par exemple, http://localhost:3000) d'effectuer des requêtes vers un autre site (par exemple, https://api.example.com), sauf si le serveur l'autorise explicitement.
Pourquoi ? Pour empêcher un attaquant de voler des données d'un autre site via votre navigateur. Sans CORS, n'importe quel script pourrait lire vos e-mails, vos comptes bancaires — une horreur.
Mais il y a un détail : CORS ne fonctionne que dans le navigateur. Postman, curl, les requêtes serveur (Node.js, Python) — ils ne vérifient pas CORS. C'est la première et principale raison pour laquelle Postman fonctionne, mais pas JavaScript.
Comment fonctionne CORS sous le capot : en termes simples
Lorsque votre JavaScript (par exemple, fetch) effectue une requête cross-origin, le navigateur fait deux choses :
- Il vérifie le type de requête.
- Si nécessaire, il envoie une requête preflight (OPTIONS).
Requête simple vs Preflight
Il existe deux types de requêtes cross-origin :
- Requête simple — si vous utilisez GET, POST ou HEAD, et que les en-têtes sont uniquement basiques (Content-Type: text/plain, application/x-www-form-urlencoded, multipart/form-data). Le navigateur envoie la requête et vérifie l'en-tête de réponse
Access-Control-Allow-Origin. - Requête Preflight — si vous utilisez des en-têtes non standard (par exemple,
Authorization), les méthodes PUT/DELETE, ou Content-Type: application/json. Le navigateur envoie d'abord une requête OPTIONS pour demander : « Puis-je effectuer une telle requête ? »
Voici un exemple de preflight en code :
fetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json', // Cela déclenche un preflight 'Authorization': 'Bearer my-token' }, body: JSON.stringify({ key: 'value' })}).then(response => response.json()).then(data => console.log(data)).catch(err => console.error('Erreur CORS :', err));Si le serveur ne répond pas à OPTIONS avec un en-tête Access-Control-Allow-Origin correct — le navigateur bloque la requête principale.
Pourquoi Postman ignore-t-il CORS ?
Postman n'est pas un navigateur. Il n'utilise pas la politique de même origine (Same-Origin Policy). Il envoie simplement une requête HTTP et reçoit une réponse. Peu importe d'où vient la requête — il ne vérifie pas les en-têtes CORS. Le serveur peut renvoyer n'importe quoi, Postman affichera la réponse.
C'est pourquoi, lorsque vous testez une API via Postman, vous voyez que le serveur fonctionne. Mais le navigateur exige que le serveur autorise explicitement l'accès depuis votre domaine.
Comment corriger l'erreur CORS : 3 méthodes concrètes
1. Configurer le serveur (la bonne approche)
Si vous avez accès au serveur, ajoutez l'en-tête Access-Control-Allow-Origin. Par exemple, sur Node.js avec Express :
const express = require('express');const app = ex