Comment obtenir un partage des ressources entre les origines (CORS)

j'ai une machine sur mon lan local (machineA) qui a deux serveurs web. La première est celle de XBMC (sur le port 8080) et affiche notre bibliothèque. Le second serveur est un script CherryPy python (port 8081) que j'utilise pour déclencher une conversion de fichier à la demande. La conversion de fichier est déclenchée par une requête AJAX POST à partir de la page servie depuis le serveur XBMC.

  • Goto http://machineA:8080 qui affiche la bibliothèque
  • la Bibliothèque est affichée
  • clique sur le lien "convert" qui émet la commande suivante -

jquery Ajax Request

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • le navigateur émet une requête D'OPTIONS HTTP avec les en-têtes suivants;

en - tête de requête-OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://machineA:8080
Access-Control-Request-Method: POST
Access-Control-Request-Headers: x-requested-with
  • le serveur répond par ce qui suit:

en - tête de réponse-OPTIONS (état = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:40:29 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1
  • la conversation s'arrête alors. Le navigateur, en théorie, devrait émettre une requête POST car le serveur a répondu avec le (?) Cors headers (Access-Control-Allow-Origin: *)

pour le dépannage, j'ai également émis le même $.poste de commandement de http://jquery.com . C'est là que je suis perplexe, jquery.com, la requête post fonctionne, une requête D'OPTIONS est envoyée à la suite par un POST. Les en-têtes de cette transaction sont ci-dessous;

en-tête de requête-OPTIONS

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Origin: http://jquery.com
Access-Control-Request-Method: POST

en-tête de réponse-OPTIONS (état = 200 OK)

Content-Length: 0
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: text/html;charset=ISO-8859-1

en-Tête de Requête POST

Host: machineA:8081
User-Agent: ... Firefox/4.01
Accept: */*
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Referer: http://jquery.com/
Content-Length: 12
Origin: http://jquery.com
Pragma: no-cache
Cache-Control: no-cache

Response Header-POST (STATUS = 200 OK)

Content-Length: 32
Access-Control-Allow-Headers: *
Access-Control-Max-Age: 1728000
Server: CherryPy/3.2.0
Date: Thu, 21 Apr 2011 22:37:59 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Content-Type: application/json

Je n'arrive pas à comprendre pourquoi la même demande fonctionnerait d'un site, mais pas de l'autre. J'espère que quelqu'un pourra me faire remarquer ce que je manque. Merci pour votre aide!

173
demandé sur James 2011-04-22 03:01:41

10 réponses

je suis finalement tombé sur ce lien " une requête POST de la CORS fonctionne à partir de javascript, mais pourquoi pas avec jQuery? "qui note que jQuery 1.5.1 ajoute le

 Access-Control-Request-Headers: x-requested-with

en-tête pour toutes les catégories de documents demandes. jQuery 1.5.2 ne fait pas cela. En outre, selon la même question, la définition d'un en-tête de réponse du serveur de

Access-Control-Allow-Headers: *

ne permet pas la réponse pour continuer. Vous devez vous assurer que l'en-tête de réponse inclut spécifiquement les en-têtes. c'est à dire:

Access-Control-Allow-Headers: x-requested-with 
134
répondu James 2017-05-23 11:54:59

REQUEST:

 $.ajax({
            url: "http://localhost:8079/students/add/",
            type: "POST",
            crossDomain: true,
            data: JSON.stringify(somejson),
            dataType: "json",
            success: function (response) {
                var resp = JSON.parse(response)
                alert(resp.status);
            },
            error: function (xhr, status) {
                alert("error");
            }
        });

réponse:

response = HttpResponse(json.dumps('{"status" : "success"}'))
response.__setitem__("Content-type", "application/json")
response.__setitem__("Access-Control-Allow-Origin", "*")

return response
55
répondu Hassan Zaheer 2013-12-06 12:02:37

m'a pris un certain temps pour trouver la solution.

si la réponse de votre serveur est correcte et que la requête est le problème, vous devez ajouter withCredentials: true au xhrFields dans la requête:

$.ajax({
    url: url,
    type: method,
    // This is the important part
    xhrFields: {
        withCredentials: true
    },
    // This is the important part
    data: data,
    success: function (response) {
        // handle the response
    },
    error: function (xhr, status) {
        // handle errors
    }
});

Remarque: jQuery >= 1.5.1 est nécessaire

9
répondu Dekel 2017-03-02 11:32:47

Eh bien, j'ai lutté avec cette question pendant quelques semaines.

la façon la plus facile, la plus conforme et la plus non-pirate de le faire est probablement d'utiliser une API JavaScript de fournisseur qui ne fait pas d'appels basés sur le navigateur et peut traiter les demandes D'origine croisée.

E. G. API JavaScript de Facebook et API Google JS.

dans le cas où votre fournisseur D'API n'est pas à jour et ne supporte pas L'en-tête Cross Origin Resource Origin '*' dans sa réponse et n'a pas d'api JS (Oui je parle de vous Yahoo ), vous êtes frappé avec l'une des trois options -

  1. en utilisant jsonp dans vos requêtes qui ajoute une fonction de rappel à votre URL où vous pouvez gérer votre réponse. Avertissement ceci va changer L'URL de la requête de sorte que votre serveur API doit être équipé pour gérer le ?callback= à la fin de L'URL.

  2. Envoyez la requête à votre serveur API qui est controller par vous et est soit dans le même domaine que le client ou a le partage de ressources D'origine croisée activé d'où vous pouvez proxy la requête vers le serveur D'API de tierce partie.

  3. probablement le plus utile dans les cas où vous faites des requêtes simples et avez besoin de gérer l'interaction utilisateur Haha! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

8
répondu Pritam Roy 2017-06-07 23:01:21

en utilisant ceci en combinaison avec Laravel résolu mon problème. Il suffit d'ajouter cet en-tête à votre requête jquery Access-Control-Request-Headers: x-requested-with et assurez-vous que la réponse côté serveur a cet en-tête Access-Control-Allow-Headers: * .

3
répondu M K 2014-04-13 02:58:24

j'ai résolu mon propre problème en utilisant l'API distance matrix de google en définissant mon en-tête de requête avec jQuery ajax. jetez un oeil ci-dessous.

var settings = {
          'cache': false,
          'dataType': "jsonp",
          "async": true,
          "crossDomain": true,
          "url": "https://maps.googleapis.com/maps/api/distancematrix/json?units=metric&origins=place_id:"+me.originPlaceId+"&destinations=place_id:"+me.destinationPlaceId+"&region=ng&units=metric&key=mykey",
          "method": "GET",
          "headers": {
              "accept": "application/json",
              "Access-Control-Allow-Origin":"*"
          }
      }

      $.ajax(settings).done(function (response) {
          console.log(response);

      });

notez ce que j'ai ajouté aux paramètres

**

"headers": {
          "accept": "application/json",
          "Access-Control-Allow-Origin":"*"
      }

**

J'espère que cette aide.

2
répondu Miracool 2018-04-13 09:42:08

pour une raison quelconque, une question sur les demandes GET a été fusionnée avec celle-ci, donc je vais y répondre ici.

cette fonction simple obtiendra de façon asynchrone une réponse D'état HTTP à partir d'une page compatible avec la fonctionnalité CORS. Si vous l'exécutez, vous verrez que seule une page avec les en-têtes appropriés retourne un statut 200 si vous accédez via XMLHttpRequest -- que GET ou POST soit utilisé. Rien ne peut être fait du côté du client pour contourner cela, sauf peut-être en utilisant JSONP si vous avez juste besoin d'un json objet.

ce qui suit peut être facilement modifié pour obtenir les données détenues dans l'objet xmlHttpRequestObject:

function checkCorsSource(source) {
  var xmlHttpRequestObject;
  if (window.XMLHttpRequest) {
    xmlHttpRequestObject = new XMLHttpRequest();
    if (xmlHttpRequestObject != null) {
      var sUrl = "";
      if (source == "google") {
        var sUrl = "https://www.google.com";
      } else {
        var sUrl = "https://httpbin.org/get";
      }
      document.getElementById("txt1").innerHTML = "Request Sent...";
      xmlHttpRequestObject.open("GET", sUrl, true);
      xmlHttpRequestObject.onreadystatechange = function() {
        if (xmlHttpRequestObject.readyState == 4 && xmlHttpRequestObject.status == 200) {
          document.getElementById("txt1").innerHTML = "200 Response received!";
        } else {
          document.getElementById("txt1").innerHTML = "200 Response failed!";
        }
      }
      xmlHttpRequestObject.send();
    } else {
      window.alert("Error creating XmlHttpRequest object. Client is not CORS enabled");
    }
  }
}
<html>
<head>
  <title>Check if page is cors</title>
</head>
<body>
  <p>A CORS-enabled source has one of the following HTTP headers:</p>
  <ul>
    <li>Access-Control-Allow-Headers: *</li>
    <li>Access-Control-Allow-Headers: x-requested-with</li>
  </ul>
  <p>Click a button to see if the page allows CORS</p>
  <form name="form1" action="" method="get">
    <input type="button" name="btn1" value="Check Google Page" onClick="checkCorsSource('google')">
    <input type="button" name="btn1" value="Check Cors Page" onClick="checkCorsSource('cors')">
  </form>
  <p id="txt1" />
</body>
</html>
1
répondu Victor Stoddard 2017-09-14 21:42:52

j'ai eu exactement le même problème où jQuery ajax m'a seulement donné des problèmes cors sur les demandes de poste où les demandes get travaillé très bien - j'ai tout fatigué ci-dessus sans résultats. J'ai eu la bonne des en-têtes dans mon serveur etc. Changer pour utiliser XMLHTTPRequest au lieu de jquery a corrigé mon problème immédiatement. Peu importe la version de jquery que j'ai utilisée, ça ne l'a pas réparé. Fetch fonctionne aussi sans problème si vous n'avez pas besoin de la compatibilité arrière du navigateur.

        var xhr = new XMLHttpRequest()
        xhr.open('POST', 'https://mywebsite.com', true)
        xhr.withCredentials = true
        xhr.onreadystatechange = function() {
          if (xhr.readyState === 2) {// do something}
        }
        xhr.setRequestHeader('Content-Type', 'application/json')
        xhr.send(json)

avec un peu de chance cela aide quelqu'un d'autre avec les mêmes problèmes.

1
répondu ozzieisaacs 2018-06-18 18:24:50

ceci est un résumé de ce qui a fonctionné pour moi:

définir une nouvelle fonction (enveloppé $.ajax pour simplifier):

jQuery.postCORS = function(url, data, func) {
  if(func == undefined) func = function(){};
  return $.ajax({
    type: 'POST', 
    url: url, 
    data: data, 
    dataType: 'json', 
    contentType: 'application/x-www-form-urlencoded', 
    xhrFields: { withCredentials: true }, 
    success: function(res) { func(res) }, 
    error: function() { 
            func({}) 
    }
  });
}

Utilisation:

$.postCORS("https://example.com/service.json",{ x : 1 },function(obj){
      if(obj.ok) {
           ...
      }
});

fonctionne aussi avec .done , .fail , etc:

$.postCORS("https://example.com/service.json",{ x : 1 }).done(function(obj){
      if(obj.ok) {
           ...
      }
}).fail(function(){
    alert("Error!");
});

côté serveur (dans ce cas où example.com est hébergé), définissez ces en-têtes (ajout d'un exemple de code en PHP):

header('Access-Control-Allow-Origin: https://not-example.com');
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Max-Age: 604800');
header("Content-type: application/json");
$array = array("ok" => $_POST["x"]);
echo json_encode($array);

C'est la seule façon savoir vraiment poster cross-domaine de JS.

JSONP convertit le POST EN GET qui peut afficher des informations sensibles dans les journaux du serveur.

1
répondu lepe 2018-07-10 21:10:01

C'est un peu tard pour la fête, mais je me bats avec ça depuis quelques jours. C'est possible et aucune des réponses que j'ai trouvées ici n'a fonctionné. C'est d'une simplicité trompeuse. Voici l' .appel ajax:

    <!DOCTYPE HTML>
    <html>
    <head>
    <body>
     <title>Javascript Test</title>
     <script src="http://code.jquery.com/jquery-latest.min.js"></script>
     <script type="text/javascript">
     $(document).domain = 'XXX.com';
     $(document).ready(function () {
     $.ajax({
        xhrFields: {cors: false},
        type: "GET",
        url: "http://XXXX.com/test.php?email='steve@XXX.com'",
        success: function (data) {
           alert(data);
        },
        error: function (x, y, z) {
           alert(x.responseText + " :EEE: " + x.status);
        }
    });
    });
    </script> 
    </body>
    </html>

Voici Le php côté serveur:

    <html>
    <head>
     <title>PHP Test</title>
     </head>
    <body>
      <?php
      header('Origin: xxx.com');
      header('Access-Control-Allow-Origin:*');
      $servername = "sqlxxx";
      $username = "xxxx";
      $password = "sss";
      $conn = new mysqli($servername, $username, $password);
      if ($conn->connect_error) {
        die( "Connection failed: " . $conn->connect_error);
      }
      $sql = "SELECT email, status, userdata  FROM msi.usersLive";
      $result = $conn->query($sql);
      if ($result->num_rows > 0) {
      while($row = $result->fetch_assoc()) {
        echo $row["email"] . ":" . $row["status"] . ":" . $row["userdata"] .  "<br>";
      }
    } else {
      echo "{ }";
    }
    $conn->close();
    ?>
    </body>
-4
répondu Steve Johnson 2016-11-03 04:29:28