L'en-tête "Access-Control-Allow-Origin" n'est pas présent sur la ressource demandée lorsque vous essayez d'obtenir des données à partir d'une API REST.
J’essaie d’obtenir des données à partir de l’API REST de HP Alm. Cela fonctionne assez bien avec un petit script curl - j'obtiens mes données.
Maintenant, faire cela avec JavaScript, fetch et ES6 (plus ou moins) semble être un plus gros problème. Je continue à obtenir ce message d'erreur :
Fetch API cannot load . La réponse à la demande de contrôle préalable ne passe pas le contrôle d'accès. passe pas le contrôle d'accès : Aucun en-tête 'Access-Control-Allow-Origin' ; n'est présent sur la ressource demandée. présent sur la ressource demandée. L'origine 'http://127.0.0.1:3000' ; est par conséquent, l'accès n'est pas autorisé. La réponse a le code d'état HTTP 501. Si une réponse opaque répond à vos besoins, réglez le mode de la demande sur 'no-cors' ; pour récupérer la ressource avec CORS désactivé.
Je comprends que c'est parce que j'essaie de récupérer ces données à partir de mon hôte local et que la solution devrait être d'utiliser CORS. Je pensais l'avoir fait, mais soit il ignore ce que j'ai écrit dans l'en-tête, soit le problème est autre ?
Alors, y a-t-il un problème d'implémentation ? Est-ce que je m'y prends mal ? Je ne peux malheureusement pas vérifier les journaux du serveur. Je suis vraiment un peu coincé ici.
function performSignIn() {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Accept', 'application/json');
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
headers.append('GET', 'POST', 'OPTIONS');
headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));
fetch(sign_in, {
//mode: 'no-cors',
credentials: 'include',
method: 'POST',
headers: headers
})
.then(response => response.json())
.then(json => console.log(json))
.catch(error => console.log('Authorization failed : ' + error.message));
}
J'utilise Chrome. J'ai également essayé d'utiliser le plugin CORS de Chrome, mais j'obtiens 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'authentification de la demande est 'include' ;. L'origine 'http://127.0.0.1:3000' ; n'est donc pas autorisée l'accès. Le mode d'informations d'identification des demandes initiées par la fonction XMLHttpRequest est contrôlé par l'attribut withCredentials.
Cette réponse couvre beaucoup de terrain, elle est donc divisée en trois parties :
Comment résoudre les problèmes de "Access-Control-Allow-Origin header must not be the wildcard ".
*Comment utiliser un proxy CORS pour contourner les problèmes de "No Access-Control-Allow-Origin header "* ? 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 juste l'absence de l'en-tête
Access-Control-Allow-Origin
nécessaire, vous pouvez toujours faire fonctionner les choses en faisant la requête à travers un proxy CORS. Pour montrer comment cela fonctionne, voici d'abord du code qui n'utilise pas de proxy CORS :La raison pour laquelle le bloc
catch
est frappé ici est que le navigateur empêche ce code d'accéder à la réponse qui revient dehttps://example.com
. Et la raison pour laquelle le navigateur fait cela est que la réponse n'a pas l'en-tête de réponseAccess-Control-Allow-Origin
. Maintenant, voici exactement le même exemple, mais avec un proxy CORS ajouté :***Remarque : Si https://cors-anywhere.herokuapp.com est en panne ou indisponible lorsque vous essayez, alors voyez ci-dessous comment déployer votre propre serveur CORS Anywhere sur Heroku en seulement 2 ou 3 minutes. Le deuxième extrait de code ci-dessus peut accéder à la réponse avec succès parce qu'en prenant l'URL de la requête et en la changeant en https://cors-anywhere.herokuapp.com/https://example.com-by, en la préfixant simplement avec l'URL du proxy, la requête est effectuée par le biais de ce proxy, ce qui a pour effet de.. :
https://example.com
.https://example.com
.Access-Control-Allow-Origin
à la réponse.Access-Control-Allow-Origin
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 2 ou 3 minutes seulement, avec 5 commandes :
Après avoir exécuté ces commandes, vous vous retrouverez avec votre propre serveur CORS Anywhere exécuté à, par exemple, https://cryptic-headland-94862.herokuapp.com/. Ainsi, au lieu de préfixer l'URL de votre requête avec
https://cors-anywhere.herokuapp.com
, préfixez-la avec l'URL de votre propre instance ; par exemple, https://cryptic-headland-94862.herokuapp.com/https://example.com. Si vous essayez d'utiliser https://cors-anywhere.herokuapp.com, vous constatez qu'il est hors service (ce qui arrive parfois), 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. Que vous utilisiez votre propre serveur ou que vous utilisiez https://cors-anywhere.herokuapp.com ou un autre proxy ouvert, cette solution fonctionnera même si la requête déclenche chez les navigateurs une requêteOPTIONS
de preflight CORS - car dans ce cas, le proxy renvoie également les en-têtesAccess-Control-Allow-Headers
etAccess-Control-Allow-Methods
nécessaires à la réussite du preflight.**Comment éviter le contrôle préalable CORS ? Le code dans la question déclenche un contrôle préalable CORS, car il envoie un en-tête
Authorization
. https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests Même sans cela, l'en-têteContent-Type : application/json
déclencherait également le contrôle préalable. Ce que "preflight" signifie : avant que le navigateur n'essaie lePOST
dans le code de la question, il enverra d'abord une requêteOPTIONS
au serveur - pour déterminer si le serveur accepte de recevoir unPOST
d'origine croisée qui inclut les en-têtesAuthorization
etContent-Type : application/json
. Cela fonctionne plutôt bien avec un petit script curl - j'obtiens mes données. Pour tester correctement aveccurl
, vous devez émuler la requête preflightOPTIONS
que le navigateur envoie :...avec
https://the.sign_in.url
remplacé par votre URLsign_in
réelle. La réponse que le navigateur doit voir à partir de cette requêteOPTIONS
doit inclure des en-têtes comme celui-ci :Si la réponse
OPTIONS
n'inclut pas ces en-têtes, le navigateur s'arrêtera là et ne tentera même pas d'envoyer la requêtePOST
. De plus, 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 tout de suite. Le serveur en question répond à la requêteOPTIONS
avec un code d'état 501, ce qui signifie apparemment qu'il essaie d'indiquer qu'il ne prend pas en charge les requêtesOPTIONS
. Les autres serveurs répondent généralement par un code d'état 405 "Method not allowed" dans ce cas. Vous ne serez donc jamais en mesure d'effectuer des requêtesPOST
directement sur ce serveur à partir de votre code JavaScript frontal si le serveur répond à cette requêteOPTIONS
avec un 405 ou 501 ou tout autre code que 200 ou 204 ou s'il 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 en amont dans le cas de la question serait la suivante :Authorization
mais s'appuie (par exemple) sur les données d'authentification intégrées dans le corps de la requêtePOST
ou comme paramètre de requêtesi le serveur n'exigeait pas que le corps de la requête
POST
ait un type de médiaContent-Type : application/json
mais acceptait à la place le corps de la requêtePOST
commeapplication/x-www-form-urlencoded
avec un paramètre nomméjson
(ou autre) dont la valeur est la donnée JSON.*Comment résoudre les problèmes de "Access-Control-Allow-Origin header must not be the wildcard "* ?
Mais ce n'est qu'un exemple ; d'autres systèmes de serveurs (web) fournissent des moyens similaires pour faire écho aux valeurs d'origine.
J'utilise Chrome. J'ai également essayé d'utiliser le plugin CORS de Chrome. Le plugin CORS de Chrome injecte apparemment, de manière simple et intelligente, un en-tête
Access-Control-Allow-Origin : *
dans la réponse que le navigateur voit. Si le plugin était plus intelligent, il mettrait la valeur de ce faux en-tête de réponseAccess-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, vous feriez mieux d'utilisercurl -H
comme ci-dessus.En ce qui concerne le code JavaScript frontal pour la requête
fetch(...)
dans la question :Supprimez ces lignes. Les en-têtes
Access-Control-Allow-*
sont des en-têtes de réponse. 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 preflight. [1] : https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Credentialed_requests_and_wildcardsCette erreur se produit lorsque l'URL du client et l'URL du serveur ne correspondent pas, y compris le numéro de port. Dans ce cas, vous devez activer votre service pour CORS, c'est-à-dire le partage des ressources entre les origines.
Si vous hébergez un service Spring REST, vous pouvez le trouver dans l'article de blog [CORS support in Spring Framework][1].
Si vous hébergez un service utilisant un serveur Node.js alors
Arrêtez le serveur Node.js.
npm install cors --save
.Ajoutez les lignes suivantes à votre server.js
var cors = require('cors' ;)
app.use(cors()) // Utilisez ceci après la déclaration de la variable
[1] : https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
Enlevez ça :