Cette réponse couvre beaucoup de terrain, elle est donc divisée en trois parties:
- Comment utiliser un proxy CORS pour contourner les problèmes «Pas d'accès-Contrôle-Autoriser l'origine»
- Comment éviter le contrôle en amont CORS
- Comment fixer « header Access-Control-Allow-Origin ne doit pas être le caractère générique » problèmes
Comment utiliser un proxy CORS pour contourner les problèmes «Pas d'accès-Contrôle-Autoriser l'origine»
Si vous ne contrôlez pas le serveur auquel votre code JavaScript frontal envoie une demande et que le problème avec la réponse de ce serveur est simplement le manque de l'en- Access-Control-Allow-Origin
tête nécessaire , vous pouvez toujours faire fonctionner les choses en faisant la demande via un Proxy CORS. Pour montrer comment cela fonctionne, voici d'abord du code qui n'utilise pas de proxy CORS:
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(url)
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
La raison pour laquelle le catch
bloc est touché est que le navigateur empêche ce code d'accéder à la réponse qui revient https://example.com
. Et la raison pour laquelle le navigateur le fait est que l'en- Access-Control-Allow-Origin
tête de réponse n'a pas d'en- tête de réponse.
Maintenant, voici exactement le même exemple mais juste avec un proxy CORS ajouté dans:
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url = "https://example.com"; // site that doesn’t send Access-Control-*
fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com
.then(response => response.text())
.then(contents => console.log(contents))
.catch(() => console.log("Can’t access " + url + " response. Blocked by browser?"))
Remarque: Si https://cors-anywhere.herokuapp.com est en panne ou indisponible lorsque vous l'essayez, voyez ci-dessous comment déployer votre propre serveur CORS Anywhere sur Heroku en seulement 2-3 minutes.
Le deuxième extrait de code ci-dessus peut accéder à la réponse avec succès, car le fait de prendre l'URL de la demande et de la modifier en https://cors-anywhere.herokuapp.com/https://example.com (en la préfixant simplement avec l'URL du proxy) provoque la demande de se faire via ce proxy, qui ensuite:
- Transmet la demande à
https://example.com
.
- Reçoit la réponse de
https://example.com
.
- Ajoute l'en-
Access-Control-Allow-Origin
tête à la réponse.
- Transmet cette réponse, avec cet en-tête ajouté, au code frontal demandeur.
Le navigateur permet ensuite au code frontal d'accéder à la réponse, car cette réponse avec l'en- Access-Control-Allow-Origin
tête de réponse est ce que le navigateur voit.
Vous pouvez facilement exécuter votre propre proxy en utilisant le code de https://github.com/Rob--W/cors-anywhere/ .
Vous pouvez également déployer facilement votre propre proxy sur Heroku en seulement 2-3 minutes, avec 5 commandes:
git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
Après avoir exécuté ces commandes, vous vous retrouverez avec votre propre serveur CORS Anywhere exécuté sur, par exemple, https://cryptic-headland-94862.herokuapp.com/ . Donc, plutôt que de préfixer l'URL de votre demande https://cors-anywhere.herokuapp.com
, préfixez-la à la place avec l'URL de votre propre instance; par exemple, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Donc, si vous essayez d'utiliser https://cors-anywhere.herokuapp.com, vous trouvez qu'il est en panne (ce qui sera parfois le cas), alors envisagez d'obtenir un compte Heroku (si ce n'est pas déjà fait) et prenez 2 ou 3 minutes pour effectuer les étapes ci-dessus pour déployer votre propre serveur CORS Anywhere sur Heroku.
Peu importe que vous exécutiez le vôtre ou que vous utilisiez https://cors-anywhere.herokuapp.com ou un autre proxy ouvert, cette solution fonctionne même si la demande est celle qui déclenche les navigateurs pour effectuer une OPTIONS
demande de contrôle en amont CORS, car dans ce cas, le le proxy renvoie également les en Access-Control-Allow-Headers
- Access-Control-Allow-Methods
têtes et nécessaires au succès du contrôle en amont.
Comment éviter le contrôle en amont CORS
Le code de la question déclenche un contrôle en amont CORS, car il envoie un en- Authorization
tête.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Même sans cela, l'en- Content-Type: application/json
tête déclencherait également le contrôle en amont.
Qu'est-ce que le «contrôle en amont» signifie: avant que le navigateur n'essaye le POST
code dans la question, il enverra d'abord une OPTIONS
demande au serveur - pour déterminer si le serveur accepte de recevoir une origine croisée POST
qui inclut les en Authorization
- Content-Type: application/json
têtes et .
Cela fonctionne assez bien avec un petit script curl - j'obtiens mes données.
Pour tester correctement avec curl
, vous devez émuler la OPTIONS
demande de contrôle en amont que le navigateur envoie:
curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type, Authorization' \
"https://the.sign_in.url"
… Avec https://the.sign_in.url
remplacé par votre sign_in
URL réelle .
La réponse que le navigateur doit voir à partir de cette OPTIONS
demande doit inclure des en-têtes comme celui-ci:
Access-Control-Allow-Origin: http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization
Si la OPTIONS
réponse n'inclut pas ces en-têtes, le navigateur s'arrêtera là et n'essaiera même jamais d'envoyer la POST
demande. En outre, le code d'état HTTP pour la réponse doit être un 2xx, généralement 200 ou 204. S'il s'agit d'un autre code d'état, le navigateur s'arrête là.
Le serveur dans la question répond à la OPTIONS
demande avec un code d'état 501, ce qui signifie apparemment qu'il essaie d'indiquer qu'il n'implémente pas la prise en charge des OPTIONS
demandes. Les autres serveurs répondent généralement avec un code d'état 405 «Méthode non autorisée» dans ce cas.
Vous ne pourrez donc jamais faire de POST
demandes directement à ce serveur à partir de votre code JavaScript frontal si le serveur répond à cette OPTIONS
demande avec un 405 ou 501 ou autre chose qu'un 200 ou 204 ou s'il ne répond pas avec ceux nécessaires en-têtes de réponse.
La façon d'éviter de déclencher un contrôle en amont pour le cas dans la question serait:
- si le serveur ne nécessitait pas d'en-
Authorization
tête de demande mais se fondait (par exemple) sur des données d'authentification intégrées dans le corps de la POST
demande ou en tant que paramètre de requête
- si le serveur n'a pas exigé que le
POST
corps ait un Content-Type: application/json
type de média mais a plutôt accepté le POST
corps comme application/x-www-form-urlencoded
avec un paramètre nommé json
(ou autre) dont la valeur est les données JSON
Comment fixer « header Access-Control-Allow-Origin ne doit pas être le caractère générique » problèmes
Je reçois un autre message d'erreur:
La valeur de l'en-tête "Access-Control-Allow-Origin" dans la réponse ne doit pas être le caractère générique "*" lorsque le mode d'informations d'identification de la demande est "include". L'origine ' http://127.0.0.1:3000 ' n'est donc pas autorisée à y accéder. Le mode d'informations d'identification des demandes lancées par XMLHttpRequest est contrôlé par l'attribut withCredentials.
Pour une demande qui inclut des informations d'identification, les navigateurs ne laisseront pas votre code JavaScript frontal accéder à la réponse si la valeur de l'en- Access-Control-Allow-Origin
tête de réponse est *
. Au lieu de cela la valeur dans ce cas , doit correspondre exactement à l'origine de votre code frontend, http://127.0.0.1:3000
.
Voir Demandes d'informations d'identification et caractères génériques dans l'article MDN HTTP access control (CORS).
Si vous contrôlez le serveur auquel vous envoyez la demande, une manière courante de traiter ce cas consiste à configurer le serveur pour qu'il prenne la valeur de l'en- Origin
tête de la demande et l'écho / la reflète dans la valeur de l'en- Access-Control-Allow-Origin
tête de la réponse. Par exemple, avec nginx:
add_header Access-Control-Allow-Origin $http_origin
Mais ce n'est qu'un exemple; d'autres systèmes de serveurs (Web) offrent des moyens similaires d'écho des valeurs d'origine.
J'utilise Chrome. J'ai également essayé d'utiliser ce plugin Chrome CORS
Ce plugin Chrome CORS injecte apparemment simplement un en- Access-Control-Allow-Origin: *
tête dans la réponse que le navigateur voit. Si le plugin était plus intelligent, ce qu'il ferait est de définir la valeur de cette fausse Access-Control-Allow-Origin
tête de réponse à l'origine réelle de votre frontend code JavaScript, http://127.0.0.1:3000
.
Évitez donc d'utiliser ce plugin, même pour les tests. C'est juste une distraction. Si vous voulez tester les réponses que vous obtenez du serveur sans navigateur les filtrant, il vaut mieux utiliser curl -H
comme ci-dessus.
En ce qui concerne le code JavaScript frontal de la fetch(…)
demande dans la question:
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Supprimez ces lignes. Les en- Access-Control-Allow-*
têtes sont des en- têtes de réponse . Vous ne voulez jamais leur envoyer de demande. Le seul effet que cela aura est de déclencher un navigateur pour effectuer un contrôle en amont.