Aucun en-tête' Access-Control-Allow-Origin ' n'est présent sur la ressource demandée-lorsque vous essayez d'obtenir des données à partir d'une API REST

j'essaie de récupérer des données de L'API REST de HP Alm. Il fonctionne assez bien avec un petit script curl - je reçois mes données.

fait maintenant cela avec JavaScript, fetch et ES6 (plus ou moins) semble être un plus grand problème. Je n'arrête pas de recevoir ce message d'erreur:

Chercher de l'API ne peut pas charger . La réponse à une demande avant le vol ne vérification du contrôle d'accès: aucun en-tête 'Access-Control-Allow-Origin' n'est présents sur la demande ressources. Origine " http://127.0.0.1:3000 " est donc pas autorisé à accéder. La réponse contenait le code D'état HTTP 501. Si une réponse opaque répond à vos besoins, définissez le mode de la requête à '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 à l'intérieur de mon hôte local et la solution devrait utiliser CORS. Maintenant je pensais que j'avais vraiment fait ça, mais d'une façon ou d'une autre ignore ce que j'écris dans l'en-tête ou le problème est autre chose?

alors, y a-t-il un problème de mise en œuvre? Suis-je le fais mal? Je ne peux pas vérifier les logs du serveur malheureusement. 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 du Chrome. J'ai également essayé d'utiliser ce Plugin Chrome CORS, mais ensuite 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 Joker ' * ' lorsque le mode d'authentification de la requête est "inclure". Origine " http://127.0.0.1:3000 " n'est donc pas admis accès. Le mode de vérification des pouvoirs XMLHttpRequest est contrôlé par l'attribut withCredentials.

132
demandé sur sideshowbarker 2017-05-09 16:47:47

4 réponses

Cette réponse, couvre beaucoup de terrain, il est donc divisé en trois parties:

  • Comment éviter le CORS de contrôle en amont
  • comment utiliser un proxy CORS pour se déplacer "No Access-Control-Allow-Origin header" problems
  • Comment réparer "Access-Control-Allow-Origin-tête ne doit pas être le" générique problèmes

Comment éviter le CORS de contrôle en amont

le code de la question déclenche un" CORS preflight "puisqu'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 vol avant.

Ce "contrôle en amont" moyens: avant que le navigateur tente le POST dans le code de la question, il faudra d'abord envoyer un OPTIONS demande au serveur - pour déterminer si le serveur est d'opter pour la réception d'un cross-origin POST qui comprend le Authorization et Content-Type: application/json en-têtes.

cela fonctionne assez bien avec un petit script curl - je reçois mes données.

pour tester correctement avec curl , vous devez émuler le preflight OPTIONS demande 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 quelque soit votre URL sign_in .

La réponse que le navigateur a besoin de voir à partir de ce OPTIONS demande doit inclure les en-têtes comme ceci:

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, alors le navigateur s'arrêtera là et ne tentera jamais d'envoyer le POST demande. De plus, le code de statut HTTP pour la réponse doit être un 2xx-typiquement 200 ou 204. Si c'est un autre code d'état, le navigateur s'arrêtera là.

le serveur de la 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 . D'autres serveurs répondent généralement avec une 405 "Méthode non autorisée" code d'état dans cette affaire.

donc vous n'allez jamais être en mesure de faire des requêtes POST directement à ce serveur à partir de votre code Javascript frontal si le serveur répond à cette requête OPTIONS avec un 405 ou 501 ou autre qu'un 200 ou 204 ou si ne répond pas avec ces en-têtes de réponse nécessaires.

la façon d'éviter de déclencher un vol avant pour le cas en question serait:

  • si le serveur ne nécessite pas Authorization en-tête de requête, mais à la place (par exemple) s'est appuyé sur des données d'authentification intégrées dans le corps de la requête POST ou comme paramètre de requête
  • si le serveur n'a pas besoin du corps POST pour avoir un type de média Content-Type: application/json mais a accepté le corps POST comme application/x-www-form-urlencoded avec un paramètre appelé json (ou autre) dont la valeur est la donnée JSON

comment utiliser un proxy CORS pour se déplacer "No Access-Control-Allow-Origin header" problems

si vous ne contrôlez pas le serveur auquel votre code JavaScript frontal envoie une requête, et 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 obtenir des choses à travailler-en faisant la demande par l'intermédiaire d'un proxy CORS. Pour montrer comment cela fonctionne, d'abord voici un certain 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é il y a, 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, c'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 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?"))

Note: Si https://cors-anywhere.herokuapp.com est en baisse ou indisponible lorsque vous l'essayez, puis voir ci-dessous pour savoir comment déployer votre propre CORS Anywhere server à Heroku en seulement 2-3 minutes.

le deuxième extrait de code ci-dessus peut accéder à la réponse avec succès car en prenant L'URL de la requête et en la changeant en https://cors-anywhere.herokuapp.com/https://example.com -en le préfixant simplement avec L'URL du proxy-provoque la requête à passer par ce proxy, qui alors:

  1. transmet la demande à https://example.com .
  2. reçoit la réponse de https://example.com .
  3. ajoute l'en-tête Access-Control-Allow-Origin à la réponse.
  4. renvoie cette réponse, avec cet en-tête ajouté, au Code frontal demandé.

le le navigateur permet alors au Code frontend d'accéder à la réponse, parce que cette réponse avec l'en-tête de réponse Access-Control-Allow-Origin est ce que le navigateur voit.

vous pouvez facilement exécuter votre propre mandataire en utilisant le code de https://github.com/Rob--W/cors-anywhere / .

Vous pouvez aussi facilement déployer votre propre mandataire à 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 finirez avec votre propre serveur CORS Anywhere tournant à, 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-la avec L'URL de votre propre instance; par exemple, https://cryptic-headland-94862.herokuapp.com/https://example.com .

donc si vous allez à essayer d'utiliser https://cors-anywhere.herokuapp.com, vous trouvez il est en baisse (qui sera parfois), puis envisager d'obtenir un compte Heroku (si vous ne le faites pas déjà) et prendre 2 ou 3 minutes pour faire les étapes ci-dessus pour déployer votre propre CORS Anywhere server sur Heroku.

peu importe, que vous exécutiez votre propre ou utilisez https://cors-anywhere.herokuapp.com ou autre proxy ouvert, Cette solution fonctionnera même si la requête est celle qui déclenche les navigateurs à faire un Preflight CORS OPTIONS demande-parce que dans ce cas, le mandataire renvoie également les en-têtes Access-Control-Allow-Headers et Access-Control-Allow-Methods nécessaires pour rendre le pré-vol réussi.


Comment réparer "Access-Control-Allow-Origin-tête ne doit pas être le" générique problèmes

je reçois un autre message d'erreur:

la valeur de La En-tête 'Access-Control-Allow-Origin' dans la réponse ne doit pas être le Joker ' * ' lorsque le mode d'authentification de la requête est "inclure". Origine " http://127.0.0.1:3000 " n'est donc pas admis accès. Le mode de vérification des pouvoirs XMLHttpRequest est contrôlé par l'attribut withCredentials.

pour une demande qui inclut les justificatifs d'identité, les navigateurs ne laisseront pas votre interface Code JavaScript accédez à la réponse si la valeur de l'en-tête de réponse Access-Control-Allow-Origin 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 Accrédités, des demandes et des caractères génériques dans le MDN HTTP de contrôle d'accès (SCRO) de l'article.

si vous contrôlez le serveur auquel vous envoyez la requête, alors une façon courante de traiter cela le cas est de configurer le serveur pour prendre la valeur de l'en-tête de requête Origin , et echo/reflect qui retourne dans la valeur de l'en-tête de réponse Access-Control-Allow-Origin . 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) fournissent des façons similaires d'afficher les valeurs d'origine.


J'utilise du Chrome. J'ai également essayé d'utiliser que Chrome CORS Plugin

que le plugin Chrome CORS injecte apparemment simplement un en-tête Access-Control-Allow-Origin: * dans la réponse que le navigateur voit. Si le plugin était plus intelligent, ce qu'il serait en train de faire est de définir la valeur de ce faux Access-Control-Allow-Origin en-tête de réponse à l'origine réelle de votre code JavaScript frontal, http://127.0.0.1:3000 .

donc évitez d'utiliser ce plugin, même pour les tests. C'est juste une distraction. Si vous voulez tester les réponses que vous obtenez à partir du serveur sans navigateur les filtrant, vous êtes mieux en utilisant curl -H comme ci-dessus.


autant que le code Javascript frontal pour la demande fetch(…) dans la question:

headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
headers.append('Access-Control-Allow-Credentials', 'true');

supprimer ces lignes. Les en-têtes Access-Control-Allow-* sont réponse en-têtes. Vous ne voulez jamais leur envoyer une demande. Le seul effet qui est de déclencher un navigateur pour faire un contrôle en amont.

253
répondu sideshowbarker 2018-06-12 08:53:37

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 qui est cross origin resource sharing.

si vous hébergez un service de repos de printemps, alors vous pouvez le trouver dans l'article de blog CORS support in Spring Framework .

si vous hébergez un service en utilisant un noeud.js serveur puis

  1. Arrêter le Nœud.js serveur.
  2. npm install de la scro
  3. Ajouter les lignes suivantes à votre serveur.js

    var cors = require('cors')
    
    app.use(cors()) // Use this after the variable declaration
    
22
répondu Rakesh 2018-02-02 01:34:58

Supprimer:

credentials: 'include',
0
répondu Nalan Madheswaran 2018-07-18 07:30:58

utiliser le type de données: "jsonp", fonctionne pour moi.

   async function get_ajax_data(){
       var _reprojected_lat_lng = await $.ajax({
                                type: 'GET',
                                dataType: 'jsonp',
                                data: {},
                                url: _reprojection_url,
                                error: function (jqXHR, textStatus, errorThrown) {
                                    console.log(jqXHR)
                                },
                                success: function (data) {
                                    console.log(data);

                                    // note: data is already json type, you just specify dataType: jsonp
                                    return data;
                                }
                            });


 } // function               
-1
répondu hoogw 2018-09-28 19:14:35