Cette réponse couvre beaucoup de choses, elle est donc divisée en trois parties :
- Comment utiliser un proxy CORS pour contourner le problème "Pas d'en-tête Access-Control-Allow-Origin" problèmes
- Comment éviter le contrôle préalable CORS
- Comment réparer "L'en-tête Access-Control-Allow-Origin ne doit pas être le joker" problèmes
Comment utiliser un proxy CORS pour contourner le problème "Pas d'en-tête Access-Control-Allow-Origin" problèmes
Si vous ne contrôlez pas le serveur auquel votre code JavaScript frontal envoie une requête, et que le problème avec la réponse de ce serveur est simplement l'absence de l'information nécessaire à l'exécution de la requête, alors vous ne pouvez pas contrôler le serveur. Access-Control-Allow-Origin
vous pouvez quand même faire fonctionner les choses en faisant passer la requête par un proxy CORS. Pour montrer comment cela fonctionne, voici d'abord un 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
est atteint, le navigateur empêche ce code d'accéder à la réponse qui revient de l'application https://example.com
. Et la raison pour laquelle le navigateur fait ça, c'est que la réponse n'a pas le caractère Access-Control-Allow-Origin
en-tête de réponse.
Maintenant, voici exactement le même exemple, mais avec un proxy CORS ajouté :
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 hors service ou indisponible au moment où vous 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 il prend l'URL de la requête et la change en https://cors-anywhere.herokuapp.com/https://example.com -en la préfixant simplement avec l'URL du proxy - fait que la demande est faite par le biais de ce proxy, qui.. :
- Transférer la demande à
https://example.com
.
- Reçoit la réponse de
https://example.com
.
- Ajoute le
Access-Control-Allow-Origin
dans la réponse.
- Transmet cette réponse, avec cet en-tête ajouté, au code frontal demandeur.
Le navigateur permet alors au code frontal d'accéder à la réponse, car cette réponse avec l'attribut Access-Control-Allow-Origin
L'en-tête de réponse est ce que le navigateur voit.
Vous pouvez facilement exécuter votre propre proxy en utilisant le code de l'application https://github.com/Rob--W/cors-anywhere/ .
Vous pouvez également déployer facilement votre propre proxy sur Heroku en 2 ou 3 minutes seulement, à l'aide de 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 fonctionnant à l'adresse suivante : par exemple, https://cryptic-headland-94862.herokuapp.com/ . Ainsi, plutôt que de préfixer l'URL de votre requête avec https://cors-anywhere.herokuapp.com
préfixez-le avec l'URL de votre propre instance, par exemple, https://cryptic-headland-94862.herokuapp.com/https://example.com .
Donc si quand vous essayez d'utiliser https://cors-anywhere.herokuapp.com, vous trouvez que c'est en panne. (ce qui sera parfois le cas), pensez à ouvrir un compte Heroku (si ce n'est pas déjà le cas) et prenez 2 ou 3 minutes pour suivre les étapes ci-dessus afin de déployer votre propre serveur CORS Anywhere sur Heroku.
Peu importe que vous gériez votre propre entreprise ou que vous utilisiez https://cors-anywhere.herokuapp.com ou un autre proxy ouvert, cette solution fonctionnera même si la requête est de celles qui déclenchent un contrôle préalable CORS de la part des navigateurs. OPTIONS
car dans ce cas, le mandataire renvoie également la requête Access-Control-Allow-Headers
y Access-Control-Allow-Methods
les en-têtes nécessaires à la réussite du contrôle en amont.
Comment éviter le contrôle préalable CORS
Le code dans la question déclenche un contrôle préalable CORS, puisqu'il envoie un fichier Authorization
en-tête.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Même sans cela, le Content-Type: application/json
déclencherait également le contrôle préalable.
Ce que signifie "preflight" : avant que le navigateur n'essaye le fichier POST
dans le code de la question, il enverra d'abord un fichier OPTIONS
pour déterminer si le serveur accepte de recevoir une demande d'origine croisée. POST
qui comprend le Authorization
y Content-Type: application/json
les en-têtes.
Cela fonctionne assez bien avec un petit curl script - j'obtiens mes données.
Pour tester correctement avec curl
vous devez émuler le contrôle en amont. OPTIONS
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 ce que votre sign_in
L'URL est.
La réponse que le navigateur doit voir de cette OPTIONS
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 le OPTIONS
n'inclut pas ces en-têtes, le navigateur s'arrêtera là et ne tentera même pas d'envoyer l'adresse de l'utilisateur. POST
demande. En outre, le code d'état HTTP de 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 au OPTIONS
avec un code d'état 501, ce qui signifie apparemment qu'il essaie d'indiquer qu'il ne met pas en œuvre la prise en charge de la norme OPTIONS
demandes. Les autres serveurs répondent généralement par un code d'état 405 "Méthode non autorisée" dans ce cas.
Donc, vous ne serez jamais en mesure de faire POST
directement à ce serveur à partir de votre code JavaScript frontal si le serveur répond à cette demande. OPTIONS
avec un 405 ou un 501 ou toute autre chose qu'un 200 ou un 204 ou si elle ne répond pas avec les en-têtes de réponse nécessaires.
La façon d'éviter de déclencher un contrôle préalable pour le cas de la question serait la suivante :
- si le serveur n'a pas besoin d'un
Authorization
mais s'appuie (par exemple) sur les données d'authentification intégrées dans le corps de l'en-tête de la demande. POST
ou comme paramètre de la requête
- si le serveur n'a pas besoin de l'option
POST
corps pour avoir un Content-Type: application/json
mais a accepté le type de média POST
corps en tant que application/x-www-form-urlencoded
avec un paramètre nommé json
(ou autre) dont la valeur est la donnée JSON
Comment réparer "L'en-tête Access-Control-Allow-Origin ne doit pas être le joker" 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'identification de la demande est include'. Origine ' http://127.0.0.1:3000 n'est donc pas autorisé accès. Le mode d'authentification des demandes initiées par l'objet XMLHttpRequest est contrôlé par l'attribut withCredentials.
Pour une requête incluant des informations d'identification, les navigateurs ne permettront pas à votre code JavaScript frontal d'accéder à la réponse si la valeur de la balise Access-Control-Allow-Origin
L'en-tête de réponse est *
. Dans ce cas, la valeur doit correspondre exactement à l'origine de votre code frontal, http://127.0.0.1:3000
.
Ver Demandes accréditées et caractères génériques dans l'article MDN sur le contrôle d'accès HTTP (CORS).
Si vous contrôlez le serveur auquel vous envoyez la requête, une façon courante de traiter ce cas est de configurer le serveur pour qu'il prenne la valeur de l'attribut Origin
et le répercute dans la valeur de l'en-tête de la requête Access-Control-Allow-Origin
l'en-tête de 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 de répercuter les valeurs d'origine.
J'utilise Chrome. J'ai également essayé d'utiliser le plugin CORS de Chrome.
Ce plugin CORS de Chrome injecte apparemment de manière simple et intelligente une Access-Control-Allow-Origin: *
dans la réponse que le navigateur voit. Si le plugin était plus intelligent, il fixerait la valeur de ce faux en-tête Access-Control-Allow-Origin
à l'origine réelle de votre code JavaScript frontal, http://127.0.0.1:3000
.
Évitez donc d'utiliser ce plugin, même pour des tests. Ce n'est qu'une distraction. Si vous voulez tester les réponses que vous obtenez du serveur sans que le navigateur ne les filtre, il est préférable d'utiliser le plugin curl -H
comme ci-dessus.
En ce qui concerne le code JavaScript frontal de l'application fetch(…)
dans la question :
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
Supprimez ces lignes. Le site Access-Control-Allow-*
Les en-têtes sont réponse les en-têtes. Vous ne devez jamais les envoyer dans une requête. Le seul effet que cela aura sera de déclencher un navigateur pour faire un contrôle préalable.