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 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 :
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 bloc catch
est frappé ici est que le navigateur empêche ce code d'accéder à la réponse qui revient de https://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éponse Access-Control-Allow-Origin
.
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
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/.git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master
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 httpsOPTIONS
de preflight CORS - car dans ce cas, le proxy renvoie également les en-têtes Access-Control-Allow-Headers
et Access-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ête Content-Type : application/json
déclencherait également le contrôle préalable.
Ce que "preflight" signifie : avant que le navigateur n'essaie le POST
dans le code de la question, il enverra d'abord une requête OPTIONS
au serveur - pour déterminer si le serveur accepte de recevoir un POST
d'origine croisée qui inclut les en-têtes Authorization
et Content-Type : application/json
.
Cela fonctionne plutôt bien avec un petit script curl - j'obtiens mes données.
Pour tester correctement avec curl
, vous devez émuler la requête preflight 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 votre URL sign_in
réelle.
La réponse que le navigateur doit voir à partir de cette requête 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 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ête POST
. 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ête OPTIONS
avec un code d'état 501, ce qui signifie apparemment qu'il essaie d'indiquer qu'il ne prend pas en charge les requêtes OPTIONS
. 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êtes POST
directement sur ce serveur à partir de votre code JavaScript frontal si le serveur répond à cette requête OPTIONS
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ête POST
ou comme paramètre de requêtePOST
ait un type de média Content-Type : application/json
mais acceptait à la place le corps de la requête POST
comme application/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 "* ?
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'authentification de la requête est 'include' ;. L'origine 'http://127.0.0.1:3000' ; n'est donc pas autorisée l'accès. Le mode d'identification des requêtes initiées par l'application 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-tête de réponse
Access-Control-Allow-Origin
est `. Dans ce cas, la valeur doit correspondre exactement à l'origine de votre code frontal,
http://127.0.0.1:3000. Voir [*Demandes créditées et caractères génériques*][1] dans l'article de 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'en-tête de requête
Originet la renvoie dans l'en-tête de réponse
Access-Control-Allow-Origin`. Par exemple, avec nginx :
add_header Access-Control-Allow-Origin $http_origin
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éponse 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, vous feriez mieux d'utiliser curl -H
comme ci-dessus.En ce qui concerne le code JavaScript frontal pour la requête fetch(...)
dans la question :
headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');
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_wildcards
Cette 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