Cómo hacer que funcione una solicitud posterior de intercambio de recursos de origen cruzado (CORS)


Tengo una máquina en mi lan local (machineA) que tiene dos servidores web. El primero es el incorporado en XBMC (en el puerto 8080) y muestra nuestra biblioteca. El segundo servidor es un script CherryPy python (puerto 8081) que estoy usando para activar una conversión de archivos bajo demanda. La conversión de archivos se activa mediante una solicitud AJAX POST desde la página servida desde el servidor XBMC.

  • Goto http://machineA:8080 que muestra la biblioteca
  • La biblioteca es mostrado
  • El usuario hace clic en el enlace' convertir ' que emite el siguiente comando -

JQuery Ajax Request

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • El navegador emite una solicitud de OPCIONES HTTP con las siguientes cabeceras;

Cabecera de solicitud-OPCIONES

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
  • El servidor responde con lo siguiente;

Response Header-OPTIONS (STATUS = 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 conversación se detiene. El navegador, debe en teoría, emitir una solicitud POST como el servidor respondió con la correcta (?) CORS headers (Access-Control-Allow-Origin:*)

Para la solución de problemas, también he emitido el mismo $.post comando desde http://jquery.com . Aquí es donde estoy perplejo, desde jquery.com, la solicitud post funciona, una solicitud de OPCIONES se envía después de un MENSAJE. Las cabeceras de esta transacción están abajo;

Cabecera de solicitud-OPCIONES

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

Encabezado de respuesta-OPCIONES (STATUS = 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

Encabezado de solicitud-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

Encabezado de respuesta-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

No puedo entender por qué la misma solicitud funcionaría desde un sitio, pero no desde el otro. Espero que alguien pueda señalar lo que me estoy perdiendo. ¡Gracias por tu ayuda!

Author: James, 2011-04-22

10 answers

Finalmente me topé con este enlace " Una solicitud de CORS POST funciona desde javascript, pero ¿por qué no con jQuery? " que señala que jQuery 1.5.1 añade el

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

Encabezado para todas las solicitudes CORS. jQuery 1.5.2 no hace esto. Además, de acuerdo con la misma pregunta, establecer un encabezado de respuesta del servidor de

Access-Control-Allow-Headers: *

No permite que la respuesta continúe. Debe asegurarse de que el encabezado de respuesta incluya específicamente los encabezados requeridos. ie:

Access-Control-Allow-Headers: x-requested-with 
 134
Author: James,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:59

SOLICITUD:

 $.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");
            }
        });

RESPUESTA:

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

return response
 55
Author: Hassan Zaheer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-06 12:02:37

Me llevó algún tiempo encontrar la solución.

En caso de que su servidor responda correctamente y la solicitud sea el problema, debe agregar withCredentials: true a xhrFields en la solicitud:

$.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
    }
});

Nota: jQuery >= 1.5.1 es requerido

 9
Author: Dekel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-02 11:32:47

Bueno, luché con este problema durante un par de semanas.

La forma más fácil, más compatible y no hackeada de hacer esto es probablemente usar una API JavaScript de proveedor que no realice llamadas basadas en el navegador y pueda manejar solicitudes de Origen cruzado.

Por ejemplo, Facebook JavaScript API y Google JS API.

En caso de que su proveedor de API no esté actualizado y no admita el encabezado Cross Origin Resource Origin '*' en su respuesta y no tenga una api JS (Sí, estoy hablando de usted Yahoo ),usted está golpeado con una de las tres opciones-

  1. Uso de jsonp en sus solicitudes que agrega una función de devolución de llamada a su URL donde puede manejar su respuesta. Advertencia esto cambiará la URL de la solicitud por lo que su servidor API debe estar equipado para manejar el ?callback= al final de la URL.

  2. Envíe la solicitud a su servidor API, que es controlador por usted y está en el mismo dominio que el cliente o tiene habilitado el Uso compartido de recursos de Origen cruzado desde donde puede proxy de la solicitud al servidor API de terceros.

  3. Probablemente más útil en los casos en los que está haciendo solicitudes OAuth y necesita manejar la interacción del usuario Jaja! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

 8
Author: Pritam Roy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-07 23:01:21

Usar esto en combinación con Laravel resolvió mi problema. Simplemente agregue este encabezado a su solicitud de jquery Access-Control-Request-Headers: x-requested-with y asegúrese de que su respuesta del lado del servidor tenga este encabezado establecido Access-Control-Allow-Headers: *.

 3
Author: M K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-13 02:58:24

Resolví mi propio problema al usar google distance matrix API configurando mi encabezado de solicitud con Jquery ajax. echa un vistazo a continuación.

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);

      });

Tenga en cuenta lo que agregué en la configuración
**

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

**
Espero que esto ayude.

 2
Author: Miracool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-13 09:42:08

Por alguna razón, una pregunta sobre las solicitudes GET se fusionó con esta, así que responderé aquí.

Esta sencilla función obtendrá asíncronamente una respuesta de estado HTTP desde una página habilitada para CORS. Si lo ejecuta, verá que solo una página con los encabezados adecuados devuelve un estado de 200 si se accede a través de XMLHttpRequest, ya sea que se use GET o POST. No se puede hacer nada en el lado del cliente para evitar esto, excepto posiblemente usando JSONP si solo necesita un objeto json.

El lo siguiente se puede modificar fácilmente para obtener los datos retenidos en el objeto 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
Author: Victor Stoddard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-14 21:42:52

Tuve exactamente el mismo problema en el que jquery ajax solo me dio problemas cors en las solicitudes post donde las solicitudes get funcionaban bien - Cansé todo lo anterior sin resultados. Tenía los encabezados correctos en mi servidor, etc. Cambiar a usar XMLHttpRequest en lugar de jquery solucionó mi problema inmediatamente. No importa qué versión de jquery utilicé no lo arreglé. Fetch también funciona sin problemas si no necesita compatibilidad con navegadores anteriores.

        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)

Esperemos que esto ayude a cualquier otra persona con el los mismos problemas.

 1
Author: ozzieisaacs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-18 18:24:50

Este es un resumen de lo que funcionó para mí:

Defina una nueva función (envuelta $.ajax para simplificar):

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({}) 
    }
  });
}

Uso:

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

También funciona con .done,.fail,etc:

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

Lado del servidor (en este caso donde example.com se aloja), establecer estas cabeceras (añadido un código de ejemplo 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);

Esta es la única manera que conozco para publicar realmente cross-domain desde JS.

JSONP convierte el POST en GET que puede mostrar información sensible en el servidor registro.

 1
Author: lepe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-10 21:10:01

Esto es un poco tarde para la fiesta, pero he estado luchando con esto durante un par de días. Es posible y ninguna de las respuestas que encontré aquí ha funcionado. Es engañosamente simple. Aquí está el .llamada 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='[email protected]'",
        success: function (data) {
           alert(data);
        },
        error: function (x, y, z) {
           alert(x.responseText + " :EEE: " + x.status);
        }
    });
    });
    </script> 
    </body>
    </html>

Aquí está el php en el lado del servidor:

    <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
Author: Steve Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-03 04:29:28