Pourquoi Postman n'obtient-il pas une erreur «Aucun en-tête« Access-Control-Allow-Origin »n'est présent sur la ressource demandée» lorsque mon code JavaScript le fait?

2503

Remarque sur le mod : cette question concerne les raisons pour lesquelles Postman n'est pas soumis aux restrictions CORS de la même manière qu'un XMLHttpRequest. Cette question n'est pas sur la façon de corriger une erreur «Pas de« contrôle d'accès-autorisation-origine »...».

Veuillez arrêter de publier :

  • Configurations CORS pour chaque langage / framework sous le soleil. Au lieu de cela, trouvez la question de votre langage / cadre pertinent .
  • Services tiers qui permettent à une demande de contourner CORS
  • Options de ligne de commande pour désactiver CORS pour divers navigateurs

J'essaie de faire une autorisation en utilisant JavaScript en me connectant au flacon intégré de l' API RESTful . Cependant, lorsque je fais la demande, j'obtiens l'erreur suivante:

XMLHttpRequest ne peut pas charger http: // myApiUrl / login . Aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L'origine 'null' n'est donc pas autorisée à accéder.

Je sais que l'API ou la ressource distante doit définir l'en-tête, mais pourquoi cela a-t-il fonctionné lorsque j'ai fait la demande via l'extension Chrome Postman ?

Voici le code de demande:

$.ajax({
    type: "POST",
    dataType: 'text',
    url: api,
    username: 'user',
    password: 'pass',
    crossDomain : true,
    xhrFields: {
        withCredentials: true
    }
})
    .done(function( data ) {
        console.log("done");
    })
    .fail( function(xhr, textStatus, errorThrown) {
        alert(xhr.responseText);
        alert(textStatus);
    });
Mr Jedi
la source
32
Faites-vous la demande de localhost ou exécutez-vous directement HTML?
MD. Sahib Bin Mahboob
@ MD.SahibBinMahboob Si je comprends votre question, je demande à localhost - j'ai une page sur mon ordinateur et je la lance. Lorsque je déploie un site sur l'hébergement, cela donne le même résultat.
M. Jedi
6
beaucoup de liens: stackoverflow.com/questions/10143093/…
cregox
8
Pour ceux qui recherchent plus de lecture, MDN a un bon article sur les requêtes ajax et cross origin: developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
Sam Eaton
1
Une remarque importante pour ce type d'erreur dans le noeud js. Vous DEVEZ définir vos en-têtes d'accès au démarrage de votre fichier server.js AVANT de commencer à configurer vos itinéraires. Sinon, tout se passera bien, mais vous obtiendrez cette erreur lorsque vous ferez des demandes depuis votre application.
Alex J

Réponses:

1346

Si j'ai bien compris, vous effectuez une requête XMLHttpRequest vers un domaine différent de celui de votre page. Le navigateur le bloque donc car il autorise généralement une demande de la même origine pour des raisons de sécurité. Vous devez faire quelque chose de différent lorsque vous souhaitez effectuer une demande interdomaine. Un tutoriel sur la façon d'y parvenir utilise CORS .

Lorsque vous utilisez Postman, ils ne sont pas limités par cette politique. Extrait de Cross-Origin XMLHttpRequest :

Les pages Web normales peuvent utiliser l'objet XMLHttpRequest pour envoyer et recevoir des données à partir de serveurs distants, mais elles sont limitées par la même stratégie d'origine. Les extensions ne sont pas si limitées. Une extension peut parler à des serveurs distants en dehors de son origine, tant qu'elle demande d'abord des autorisations d'origine croisée.

MARYLAND. Sahib Bin Mahboob
la source
7
Tu as raison. Je fais une demande à un domaine différent de celui de ma page. L'API est sur le serveur et j'exécute la demande de localhost. Avant d'accepter la réponse, pouvez-vous m'expliquer ce que signifie "exécuter la demande directement"? POSTMAN n'utilise pas de domaine?
M. Jedi
181
Le navigateur ne bloque pas la demande. Le seul navigateur qui bloque purement et simplement les requêtes ajax d'origine croisée est IE7 ou une version antérieure. Tous les navigateurs, autres que IE7 et les versions antérieures, implémentent la spécification CORS (IE8 et IE9 partiellement). Il vous suffit de vous inscrire aux demandes CORS sur votre serveur API en renvoyant les en-têtes appropriés en fonction de la demande. Vous devriez lire les concepts CORS sur mzl.la/VOFrSz . Postman envoie également des demandes via XHR. Si vous ne voyez pas le même problème lors de l'utilisation de postman, cela signifie que vous n'envoyez pas sans le savoir la même demande via postman.
Ray Nicholus
10
@ MD.SahibBinMahboob Postman n'envoie PAS de demande "depuis votre code java / python". Il envoie la demande directement depuis le navigateur. Les extensions XHR dans Chrome fonctionnent un peu différemment, en particulier lorsque des demandes d'origine croisée sont impliquées .
Ray Nicholus
250

AVERTISSEMENT: l' utilisation Access-Control-Allow-Origin: *peut rendre votre API / site Web vulnérable aux attaques de contrefaçon de demande intersite (CSRF). Assurez-vous de bien comprendre les risques avant d'utiliser ce code.

C'est très simple à résoudre si vous utilisez PHP . Ajoutez simplement le script suivant au début de votre page PHP qui gère la requête:

<?php header('Access-Control-Allow-Origin: *'); ?>

Si vous utilisez Node-red, vous devez autoriser CORS dans le node-red/settings.jsfichier en supprimant les commentaires des lignes suivantes:

// The following property can be used to configure cross-origin resource sharing
// in the HTTP nodes.
// See https://github.com/troygoode/node-cors#configuration-options for
// details on its contents. The following is a basic permissive set of options:
httpNodeCors: {
 origin: "*",
 methods: "GET,PUT,POST,DELETE"
},

Si vous utilisez Flask identique à la question; vous devez d'abord installerflask-cors

$ pip install -U flask-cors

Incluez ensuite les cors Flask dans votre application.

from flask_cors import CORS

Une application simple ressemblera à:

from flask import Flask
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

@app.route("/")
def helloWorld():
  return "Hello, cross-origin-world!"

Pour plus de détails, vous pouvez consulter la documentation de Flask .

Shady Sherif
la source
93
et ce n'est pas sûr
llazzaro
153
Vous ne devez pas désactiver CORS car vous ne savez pas à quoi il sert. C'est une réponse terrible.
meagar
124
Même s’il n’était pas sûr, la question n’était pas la sécurité, mais comment accomplir la tâche. C'est l'une des options qu'un développeur doit choisir lorsqu'il traite des demandes AJAX interdomaines. Cela m'a aidé à résoudre le problème et pour mon application, je me fiche de l'origine des données. Je désinfecte toutes les entrées avec PHP sur le domaine de destination, donc, si quelqu'un veut y publier du courrier indésirable, laissez-le essayer. Le point principal ici est, AJAX inter-domaine peut être autorisé à partir du domaine de destination. +1 pour la réponse.
ZurabWeb le
23
Bien que je sois d'accord avec le message général que Piero donne, il ne s'agit pas spécifiquement de sécurité, mais la sécurité est une préoccupation. Je pense que cela aurait au moins dû dire quelque chose comme "C'est généralement mauvais! Ne faites pas cela à moins de savoir ce que vous faites! Voici plus de documentation à ce sujet: ...", et peut-être expliquer brièvement pourquoi. Je détesterais que quelqu'un vienne ici et pense simplement "Oh, je peux simplement ajouter / ajuster cet en-tête et je suis bon!" et ne connais pas toutes les ramifications. Je veux dire, c'est un peu sur eux de faire des recherches et tout, mais quand même.
Thomas F.
4
J'aime cette réponse ... J'ai le même problème et ça le résout ... Il a expliqué qu'il y a des problèmes de sécurité, mais c'est un autre problème et laissez chacun individuellement réfléchir et résoudre ce problème ...
Ari Waisberg
64

Parce que
$ .ajax ({type: "POST" - appelle OPTIONS
$ .post ( - Appelle POST

Les deux sont différents. Postman appelle correctement "POST", mais lorsque nous l'appellerons, ce sera "OPTIONS".

Pour les services Web C # - API Web

Veuillez ajouter le code suivant dans votre fichier web.config sous la balise <system.webServer>. Cela fonctionnera:

<httpProtocol>
    <customHeaders>
        <add name="Access-Control-Allow-Origin" value="*" />
    </customHeaders>
</httpProtocol>

Veuillez vous assurer que vous ne faites aucune erreur dans l'appel Ajax

jQuery

$.ajax({
    url: 'http://mysite.microsoft.sample.xyz.com/api/mycall',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    type: "POST", /* or type:"GET" or type:"PUT" */
    dataType: "json",
    data: {
    },
    success: function (result) {
        console.log(result);
    },
    error: function () {
        console.log("error");
    }
});

Note: Si vous cherchez le téléchargement de contenu à partir d' un site Web tiers alors cela ne vous aidera pas . Vous pouvez essayer le code suivant, mais pas JavaScript.

System.Net.WebClient wc = new System.Net.WebClient();
string str = wc.DownloadString("http://mysite.microsoft.sample.xyz.com/api/mycall");
George Livingston
la source
Cette configuration a résolu la même erreur sur Wordpress dans Azure Services. Merci.
Andre Mesquita
9
Je suggère d'utiliser une valeur d'origine spécifique pour éviter les demandes de domaines externes. Ainsi, par exemple, au lieu d' *utiliserhttps://www.myotherdomain.com
pechar
Le lien hubfly.com/blog/solutions/how-to-fix-angular-4-api-call-issues est rompu (404).
Peter Mortensen
8

L'application d'une restriction CORS est une fonctionnalité de sécurité définie par un serveur et implémentée par un navigateur .

Le navigateur regarde la politique CORS du serveur et la respecte.

Cependant, l'outil Postman ne se soucie pas de la stratégie CORS du serveur.

C'est pourquoi l'erreur CORS apparaît dans le navigateur, mais pas dans Postman.

Gopinath
la source
1
Oui, je ne saurais trop insister sur la raison pour laquelle ce petit détail mérite une certaine attention. Lorsque l'on parle de sécurité, il est primordial de mentionner que CORS n'est aussi solide que le client qui l' implémente. Imaginez donc que vous preniez un simple HttpClient (code côté serveur) et que vous construisiez un proxy, qui fera ensuite vos demandes ... La sécurité peut être complètement contournée, laissant vraiment la norme CORS comme une mauvaise solution
Christopher Bonitz
7

Dans l'enquête ci-dessous en tant qu'API, j'utilise http://example.com au lieu de http: // myApiUrl / login à partir de votre question, car cette première fonctionne.

Je suppose que votre page est sur http: //my-site.local: 8088 .

La raison pour laquelle vous voyez des résultats différents est que Postman:

  • définir l'en-tête Host=example.com(votre API)
  • PAS définir l'en-tête Origin

Ceci est similaire à la façon dont les navigateurs envoient des demandes lorsque le site et l'API ont le même domaine (les navigateurs définissent également l'élément d'en-tête Referer=http://my-site.local:8088, mais je ne le vois pas dans Postman). Lorsque l'en- Origintête n'est pas défini, les serveurs autorisent généralement de telles demandes par défaut.

Entrez la description de l'image ici

C'est la manière standard dont Postman envoie les demandes. Mais un navigateur envoie des demandes différemment lorsque votre site et votre API ont des domaines différents , puis CORS se produit et le navigateur automatiquement:

  • définit l'en-tête Host=example.com(le vôtre comme API)
  • définit l'en-tête Origin=http://my-site.local:8088(votre site)

(L'en-tête Referera la même valeur que Origin). Et maintenant, dans l' onglet Console et réseaux de Chrome, vous verrez:

Entrez la description de l'image ici

Entrez la description de l'image ici

Lorsque vous disposez de Host != OriginCORS, et lorsque le serveur détecte une telle demande, il la bloque généralement par défaut .

Origin=nullest défini lorsque vous ouvrez du contenu HTML à partir d'un répertoire local et envoie une demande. La même situation se produit lorsque vous envoyez une demande à l'intérieur d'un <iframe>, comme dans l'extrait ci-dessous (mais ici l'en- Hosttête n'est pas défini du tout) - en général, partout où la spécification HTML dit origine opaque, vous pouvez traduire cela en Origin=null. Vous trouverez plus d'informations à ce sujet ici .

fetch('http://example.com/api', {method: 'POST'});
Look on chrome-console > network tab

Si vous n'utilisez pas une simple demande CORS, généralement le navigateur envoie automatiquement une demande OPTIONS avant d'envoyer la demande principale - plus d'informations sont ici . L'extrait ci-dessous le montre:

fetch('http://example.com/api', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json'}
});
Look in chrome-console -> network tab to 'api' request.
This is the OPTIONS request (the server does not allow sending a POST request)

Vous pouvez modifier la configuration de votre serveur pour autoriser les requêtes CORS.

Voici un exemple de configuration qui active CORS sur nginx (fichier nginx.conf) - soyez très prudent avec le réglage always/"$http_origin"pour nginx et "*"pour Apache - cela débloquera CORS de n'importe quel domaine.

Voici un exemple de configuration qui active CORS sur Apache (fichier .htaccess)

Kamil Kiełczewski
la source
2

Rencontré la même erreur dans différents cas d'utilisation.

Cas d'utilisation: en chrome lorsque vous essayez d'appeler le point final Spring REST en angulaire.

entrez la description de l'image ici

Solution: ajoutez une annotation @CrossOrigin ("*") au-dessus de la classe de contrôleur respective.

entrez la description de l'image ici

Kms
la source
J'utilise localhost au lieu de * pour la sécurité
neo7bf
-1

Si vous utilisez .NET comme niveau intermédiaire, vérifiez clairement l'attribut de route, par exemple,

J'ai eu un problème quand c'était comme ça,

[Route("something/{somethingLong: long}")] //Space.

Fixé par cela,

[Route("something/{somethingLong:long}")] //No space
Sai Vaibhav Medavarapu
la source
-1

Uniquement pour le projet d'API Web .NET Core, ajoutez les modifications suivantes:

  1. Ajoutez le code suivant après la services.AddMvc()ligne dans la ConfigureServices()méthode du fichier Startup.cs:
services.AddCors(allowsites=>{allowsites.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
  1. Ajoutez le code suivant après la app.UseMvc()ligne dans la Configure()méthode du fichier Startup.cs:
app.UseCors(options => options.AllowAnyOrigin());
  1. Ouvrez le contrôleur auquel vous souhaitez accéder en dehors du domaine et ajoutez cet attribut suivant au niveau du contrôleur:
[EnableCors("AllowOrigin")]
Shakti Srivastav
la source