CORS Expliqué Pourquoi votre requête fonctionne avec curl mais échoue dans le navigateur
Les erreurs CORS ressentent comme des bugs du serveur. Ce n'est pas le cas. Ce sont des vérifications de permission imposées par le navigateur. Comprenez la politique d'origine identique, les requêtes préliminaires et les cinq en-têtes importants — et corrigez chaque erreur CORS en moins de cinq minutes.
Vous écrivez un fetch() appel. Il fonctionne parfaitement avec curl. Vous ouvrez le navigateur, vous cliquez sur l'endpoint et vous êtes frappé par :
Access to fetch at 'https://api.example.com/data' from origin 'https://yourapp.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
Vous faites une recherche sur Google. Stack Overflow vous dit d'ajouter une en-tête. Vous ajoutez l'en-tête. Un autre erreur apparait. Vous ajoutez une autre en-tête. Maintenant, c'est une erreur de pré-évaluation. Deux heures plus tard, vous désactivez entièrement CORS dans Chrome grâce à un drapeau trouvé dans une réponse de 2016. Vous le déployez en production ainsi et espérez que personne ne le remarque.
Cet article existe pour empêcher cela de se produire. CORS prend environ 10 minutes à comprendre correctement, et une fois que vous l'avez compris, vous le corrigez en 2 minutes chaque fois.
Ce n'est pas une erreur du serveur. C'est une règle du navigateur.
C'est la chose la plus importante à comprendre sur CORS : elle est entièrement imposée par le navigateur. Le serveur ne bloque pas votre requête. C'est le navigateur qui le fait, après que le serveur a déjà répondu.
C'est pourquoi curl fonctionne. curl ne respecte pas CORS. Ni Postman. Ni votre backend appelant un autre backend. CORS ne s'active que lorsque le navigateur fait une requête croisée en faveur d'une page web.
Le rôle du serveur est de dire s'il autorise l'accès croisé via des en-têtes de réponse. Le rôle du navigateur est de vérifier ces en-têtes et de décider s'il remet la réponse à votre JavaScript. Si les en-têtes ne sont pas corrects, le navigateur jette la réponse et lance une erreur — même si la requête est terminée et que le serveur a renvoyé des données.
Pourquoi le Navigateur Fait Cela (La Politique d'Origine Identique)
La Politique d'Origine Identique (SOP) est une règle de sécurité du navigateur qui empêche JavaScript exécuté sur https://evil.com de lire les réponses provenant de https://yourbank.com. Sans cela, tout site pourrait faire des requêtes authentifiées en votre nom et lire les résultats sans que vous le sachiez.
Deux URLs ont la même origine si leurs schéma, hôte et port sont identiques :
https://app.example.comethttps://api.example.com— origines différentes (sous-domaine différent)http://example.comethttps://example.com— origines différentes (schéma différent)https://example.comethttps://example.com:8080— origines différentes (port différent)https://example.com/fooethttps://example.com/bar— même origine (le chemin n'est pas pris en compte)
CORS est la manière dont les serveurs s'engagent à affaiblir la SOP pour des origines spécifiques. Ce n'est pas une contournement — c'est une autorisation explicite.
Requêtes simples vs. Requêtes pré-évaluées
Toutes les requêtes croisées ne déclenchent pas une pré-évaluation. Le navigateur divise les requêtes en deux catégories.
Requêtes simples elles passent directement (aucune vérification OPTIONS en premier). Une requête est « simple » lorsqu'elle satisfait toutes les conditions suivantes :
- La méthode est GET, POST ou HEAD
- Le type de contenu est
application/x-www-form-urlencoded,multipart/form-data, outext/plain - Aucun en-tête personnalisé au-delà du liste des en-têtes sécurisés par CORS
Requêtes pré-évaluées sont tout ce qui n'est pas simple — toute méthode PUT/PATCH/DELETE, tout application/json corps, tout en-tête personnalisé comme Authorization ou X-API-Key. Avant la requête réelle, le navigateur envoie automatiquement une requête OPTIONS pour demander : « est-ce que vous permettez cela ? »
Quelle est la véritable échange d'une pré-évaluation
Voici un véritable échange de pré-évaluation. Votre frontend appelle fetch('https://api.example.com/users', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer token' } }).
Le navigateur envoie automatiquement cette requête OPTIONS — vous n'écrit jamais ce code :
OPTIONS /users HTTP/1.1
Host: api.example.com
Origin: https://yourapp.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization, content-type
Le serveur doit répondre avec des en-têtes confirmant qu'il autorise cela :
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://yourapp.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
Seulement si la pré-évaluation réussit, le navigateur envoie la requête POST réelle. Si un en-tête de pré-évaluation est manquant ou incorrect, la requête réelle ne quitte jamais le navigateur.
Access-Control-Max-Age: 86400 le résultat de la pré-évaluation est stocké pendant 24 heures afin que le navigateur ne répète pas ce dialogue à chaque requête. Il vaut la peine de le configurer.
Les En-têtes qui Importent Vraiment
Access-Control-Allow-Origin — l'en-tête requis. Soit une origine spécifique (https://yourapp.com) soit * pour toute origine. Vous ne pouvez pas utiliser * lorsque vous envoyez des informations d'authentification (cookies, en-têtes Authorization).
Access-Control-Allow-Methods — obligatoire pour les requêtes pré-évaluées. Liste toutes les méthodes que vous souhaitez autoriser. Incluez toujours OPTIONS, sinon certains serveurs retournent une erreur 405 lors de la pré-évaluation.
Access-Control-Allow-Headers — obligatoire lorsque la requête inclut des en-têtes personnalisés. Doit explicitement lister tous les en-têtes non sécurisés que votre frontend envoie. L'absence de Authorization ici est responsable d'environ 40% de tickets de support CORS.
Access-Control-Allow-Credentials: true — obligatoire uniquement lorsque vous envoyez des cookies ou des authentifications HTTP. Doit également être défini sur l'appel fetch. Lorsque cette valeur est true, credentials: 'include' doit être une origine explicite — Allow-Origin ne fonctionne pas et vous obtenez une erreur distincte. * Access-Control-Expose-Headers
— les en-têtes de réponse que votre frontend peut lire. Par défaut, JavaScript ne peut accéder qu'à un petit ensemble sécurisé (Content-Type, Cache-Control, etc.). Si vous devez lire un en-tête personnalisé comme dans votre gestionnaire de réponse, ajoutez-le ici. X-Request-Id Cinq erreurs qui coûtent des heures
1. Utilisation d'une étoile avec des informations d'authentification.
et puis vous vous demandez pourquoi les requêtes avec informations d'authentification échouent. La spécification interdit explicitement les étoiles lorsqu'il s'agit d'informations d'authentification. Vous devez refléter l'origine spécifique : lisez l'en-tête de la requête et répétez-le dans la réponse. Paramètre Access-Control-Allow-Origin: * 2. Ne pas gérer les requêtes OPTIONS du tout. Origin Express, FastAPI et la plupart des frameworks ne répondent pas automatiquement aux requêtes OPTIONS avec des en-têtes CORS. Si votre middleware CORS ne fonctionne que sur les endpoints réels et non sur la route de pré-évaluation, chaque requête avec informations d'authentification ou non-simple échouera. La solution : assurez-vous que votre middleware CORS fonctionne avant votre routeur, ou gérez explicitement les requêtes OPTIONS.
3. Retourner les en-têtes CORS uniquement en cas de succès. Si votre serveur retourne une erreur 4xx ou 5xx sans en-têtes CORS, le navigateur cache le code d'état réel de JavaScript. Votre gestionnaire d'erreur reçoit une erreur réseau générique sans code d'état. Retournez toujours
sur chaque réponse, pas seulement sur les 200. 4. Oublier le port. Access-Control-Allow-Origin sont des origines différentes. Pendant le développement local, vous rencontrerez fréquemment un backend sur le port 8080 depuis un frontend sur 3000. Les deux ports doivent être inclus dans votre liste d'origines autorisées, ou vous avez besoin d'un proxy de développement.
5. Stocker un pré-évaluation mauvaise. https://app.example.com et https://app.example.com:3000 stocke le résultat de la pré-évaluation. Si vous le définissez à 86400 et que vous mettez à jour vos en-têtes autorisés, les navigateurs avec le résultat (faux) stocké continueront à échouer pendant jusqu'à 24 heures. Pendant le développement, définissez-le à 0 ou désactivez-le avec un rafraîchissement forcé + désactivation du cache dans DevTools.
5. Mise en cache d'une requête préliminaire incorrecte. Access-Control-Max-Age Mise en cache de la requête préliminaire. Si vous la définissez sur 86400 et que vous modifiez ensuite les en-têtes autorisés, les navigateurs avec le cache (faux) de la requête préliminaire continueront à échouer pendant jusqu'à 24 heures. En développement, définissez cette valeur sur 0 ou effacez-la en effectuant un rafraîchissement forcé et en désactivant le cache dans DevTools.
Solutions rapides selon les scénarios
Frontend + backend sur des domaines différents, sans cookies : Ajouter Access-Control-Allow-Origin: * (ou l'origine spécifique du frontend) à votre serveur. C'est tout.
Frontend + backend sur des domaines différents, avec cookies/auth : Vous avez besoin de Access-Control-Allow-Origin: https://yourfrontend.com (explicite, sans étoile) et Access-Control-Allow-Credentials: true sur le serveur, ainsi que credentials: 'include' dans votre appel fetch. Les cookies doivent aussi avoir SameSite=None; Secure pour traverser les origines.
Développement local vers une API distante que vous ne controlez pas : Ajoutez un proxy de développement dans votre outil de build. Vite : server.proxy. webpack-dev-server : devServer.proxy. Next.js : rewrites. Ce proxy fait croire au navigateur que toutes les requêtes sont d'origine identique ; CORS ne se déclenche jamais.
API Gateway / CDN en avant : Assurez-vous que la requête OPTIONS ne soit pas absorbée avant d'atteindre votre origine. AWS API Gateway et CloudFront ont des paramètres CORS qui peuvent entrer en conflit avec vos en-têtes d'applications — si vous définissez des en-têtes dans les deux endroits, vous obtenez souvent des valeurs d'en-têtes dupliquées, ce qui échoue également.
Si vous devez vérifier les en-têtes exactes que votre serveur retourne, le Constructeur et validateur d'en-têtes CORS sur IO Tools vous permet de construire et d'inspecter l'ensemble des en-têtes sans écrire une seule ligne de code. Utile pour vérifier ce que retourne réellement un backend par rapport à ce que vous pensez qu'il retourne.
Les erreurs CORS ressemblent à des bugs de serveur car le message d'erreur mentionne le serveur. Elles sont des vérifications d'autorisation imposées par le navigateur — et une fois que vous savez quel en-tête est manquant et pourquoi, chaque erreur CORS se résout en quelques minutes. Construisez les bons en-têtes avec le Constructeur d'En-têtes CORS ou testez la structure brute de votre requête avec le Générateur de commande cURL pour éliminer les erreurs d'origine avant de toucher la configuration du serveur.
Vous aimerez peut-être aussi
Installez nos extensions
Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide
恵 Le Tableau de Bord Est Arrivé !
Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !
Outils essentiels
Tout voir Nouveautés
Tout voirMise à jour: Notre dernier outil was added on Juin 26, 2026
