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-Origintê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 catchbloc 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-Origintê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-Origintê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-Origintê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 OPTIONSdemande de contrôle en amont CORS, car dans ce cas, le le proxy renvoie également les en Access-Control-Allow-Headers- Access-Control-Allow-Methodstê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- Authorizationtête.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests
Même sans cela, l'en- Content-Type: application/jsontê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 POSTcode dans la question, il enverra d'abord une OPTIONSdemande au serveur - pour déterminer si le serveur accepte de recevoir une origine croisée POSTqui inclut les en Authorization- Content-Type: application/jsontê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 OPTIONSdemande 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.urlremplacé par votre sign_inURL réelle .
La réponse que le navigateur doit voir à partir de cette OPTIONSdemande 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 OPTIONSréponse n'inclut pas ces en-têtes, le navigateur s'arrêtera là et n'essaiera même jamais d'envoyer la POSTdemande. 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 OPTIONSdemande 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 OPTIONSdemandes. 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 POSTdemandes directement à ce serveur à partir de votre code JavaScript frontal si le serveur répond à cette OPTIONSdemande 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-
Authorizationtête de demande mais se fondait (par exemple) sur des données d'authentification intégrées dans le corps de la POSTdemande ou en tant que paramètre de requête
- si le serveur n'a pas exigé que le
POSTcorps ait un Content-Type: application/jsontype de média mais a plutôt accepté le POSTcorps comme application/x-www-form-urlencodedavec 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-Origintê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- Origintête de la demande et l'écho / la reflète dans la valeur de l'en- Access-Control-Allow-Origintê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-Origintê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 -Hcomme 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.