CORS en JavaScript : pourquoi le navigateur bloque votre appel d'API

Le CORS autorise une page à lire la réponse d'une autre origine. L'erreur vient du navigateur, et la solution se trouve toujours côté serveur appelé.
4 min de lecture
Believemy logo

Le premier appel vers une API hébergée ailleurs se termine presque toujours de la même façon : la console affiche un message de blocage, l'onglet réseau montre pourtant une réponse arrivée, et le code n'y a pas accès.

Ce mécanisme n'est ni un bug ni une sévérité inutile. Il empêche une page quelconque de lire, avec vos cookies, les données d'un site où vous êtes connecté.


Définition

Le CORS, pour partage des ressources entre origines, est le protocole par lequel un serveur autorise une page d'une autre origine à lire ses réponses. L'autorisation passe par des en-têtes HTTP, et c'est le navigateur qui la vérifie.

Rien ne s'écrit côté page pour la débloquer : un appel fetch() refusé se règle sur le serveur appelé, ou pas du tout.

Trois scénarios CORS comparés sur la même échelle de tempsUne requête simple coûte un aller-retour. Une requête préparatoire en coûte deux : le OPTIONS puis la vraie requête. Une fois la permission mise en cache, on retombe à un seul.Le pré-vol, un aller-retour avant la requêteChaque bloc est un aller-retour avec le serveurRequête simple : GET, sans en-tête sur mesureGET /api1 aller-retourRequête préparatoire : POST en JSONOPTIONSPOST /api2 allers-retoursAppel suivant : la permission est en cachePOST /apitemps économisé1 aller-retourLe pré-vol double la latence, la mise en cache l'annule


Ce qu'est une origine

Une origine est le trio protocole, domaine et port. Une seule différence suffit à changer d'origine, ce que le tableau montre sur trois colonnes pour une page servie depuis https://app.exemple.com.

URL appeléeMême origineCe qui diffère
https://app.exemple.com/apiOuiRien, seul le chemin change
https://api.exemple.comNonLe sous-domaine
http://app.exemple.comNonLe protocole
https://app.exemple.com:8443NonLe port

La deuxième ligne surprend souvent : un sous-domaine du même site reste une autre origine, et demande donc une autorisation explicite.


La requête préparatoire

Certaines requêtes partent directement. D'autres sont précédées d'un appel OPTIONS automatique, qui demande la permission avant d'envoyer quoi que ce soit. Ce détour se déclenche dès qu'une requête sort du cadre le plus simple : une méthode autre que GET ou POST, un en-tête sur mesure, ou un corps annoncé en application/json.

JAVASCRIPT
// Côté serveur, la réponse doit porter ces en-têtes
function autoriser(reponse, origine) {
  reponse.setHeader("Access-Control-Allow-Origin", origine);
  reponse.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE");
  reponse.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
  reponse.setHeader("Access-Control-Max-Age", "86400");
}

Le dernier en-tête met la permission en cache, ce qui évite un aller-retour supplémentaire avant chaque appel. Chaque navigateur applique son propre plafond, souvent bien plus bas que la valeur demandée.

Bon à savoir

Le blocage protège la lecture de la réponse, pas le serveur. Une requête simple atteint bel et bien la destination avant d'être bloquée à la lecture : une écriture doit donc rester protégée côté serveur, indépendamment de ce mécanisme.


Questions fréquentes

Question

Pourquoi le même appel fonctionne-t-il depuis un client REST ?

Parce que la règle est appliquée par le navigateur, et par lui seul. Ni un client comme Postman, ni une commande curl, ni un script Node.js ne tiennent compte de ces en-têtes. Un appel qui répond correctement en ligne de commande et échoue dans l'onglet est donc parfaitement normal.


Question

Peut-on contourner le blocage depuis la page ?

Non, et c'est voulu. L'option mode: "no-cors" laisse partir la requête mais rend une réponse opaque, dont ni le corps ni le statut ne sont lisibles. La seule solution durable consiste à passer par votre propre serveur, qui appelle l'API et vous renvoie le résultat depuis votre origine.


Question

Pourquoi l'étoile ne marche-t-elle pas avec les cookies ?

Parce que la valeur * est incompatible avec un appel qui transporte des identifiants. Il faut alors renvoyer l'origine exacte de l'appelant dans Access-Control-Allow-Origin, ajouter Access-Control-Allow-Credentials à vrai, et régler credentials sur include côté page. Cette configuration se met en place pas à pas dans la formation Node.js.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.