Как заставить работать почтовый запрос на совместное использование ресурсов (CORS)

У меня есть машина в моей локальной сети (machineA) с двумя веб-серверами. Первый - встроенный в XBMC (на порту 8080) и отображает нашу библиотеку. Второй сервер - это скрипт Python CherryPy (порт 8081), который я использую для запуска преобразования файла по запросу. Преобразование файла запускается запросом AJAX POST со страницы, обслуживаемой сервером XBMC.

  • Перейти к http://machineA:8080, который отображает библиотеку
  • Библиотека отображается
  • Пользователь нажимает ссылку «преобразовать», которая запускает следующую команду -

jQuery Ajax Request

$.post('http://machineA:8081', {file_url: 'asfd'}, function(d){console.log(d)})
  • Браузер выдает запрос HTTP 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
  • Сервер отвечает следующим образом:

Заголовок ответа - ОПЦИИ (СОСТОЯНИЕ = 200 ОК)

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
  • Затем разговор прекращается. Теоретически браузер должен выдавать запрос POST, поскольку сервер ответил правильными (?) Заголовками CORS (Access-Control-Allow-Origin: *)

Для устранения неполадок я также выполнил ту же команду $ .post из http://jquery.com. Вот где я в тупике, с jquery.com, почтовый запрос работает, запрос OPTIONS отправляется после POST. Заголовки этой транзакции приведены ниже;

Заголовок запроса - ОПЦИИ

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

Заголовок ответа - ОПЦИИ (СОСТОЯНИЕ = 200 ОК)

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

Заголовок запроса - 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

Заголовок ответа - 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

Я не могу понять, почему один и тот же запрос будет работать с одного сайта, а другой - нет. Я надеюсь, что кто-нибудь сможет указать на то, что мне не хватает. Спасибо за вашу помощь!


person James    schedule 21.04.2011    source источник
comment
Нужен ли CORS, если оба веб-сервера находятся на одном компьютере?   -  person jdigital    schedule 22.04.2011
comment
Насколько мне известно, это запрос CORS из-за другого порта. Кроме того, запрос OPTIONS указывает, что браузер обрабатывает его как запрос CORS.   -  person James    schedule 22.04.2011
comment
Возможный дубликат CORS POST запрос работает с простым javascript, но почему не с jQuery?   -  person Liam    schedule 27.02.2018


Ответы (11)


Наконец я наткнулся на ссылку "Запрос CORS POST работает с простым javascript, но почему не с jQuery? ", в котором отмечается, что jQuery 1.5.1 добавляет

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

заголовок ко всем запросам CORS. jQuery 1.5.2 этого не делает. Кроме того, согласно тому же вопросу, установка заголовка ответа сервера

Access-Control-Allow-Headers: *

не позволяет продолжить ответ. Вам необходимо убедиться, что заголовок ответа специально включает требуемые заголовки. то есть:

Access-Control-Allow-Headers: x-requested-with 
person James    schedule 22.04.2011

ЗАПРОС:

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

ОТКЛИК:

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

return response
person Hassan Zaheer    schedule 06.12.2013
comment
если сервер не принимает перекрестное происхождение, crossdomain = true не должно решать проблему. использование dataType: jsonp и установка обратного вызова, например jsonpCallback: response, было бы лучшей идеей для этого. См. Также: api.jquery.com/jquery.ajax. - person BonifatiusK; 13.11.2014

Я решил свою собственную проблему при использовании API матрицы расстояний Google, установив заголовок своего запроса с помощью JQuery ajax. посмотрите ниже.

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

      });

Обратите внимание, что я добавил в настройках
**

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

**
Надеюсь, это поможет.

person Miracool    schedule 13.04.2018
comment
это единственное решение, которое сработало для нас, ничего не меняя на стороне сервера ... спасибо miracool - person Timsta; 14.07.2018
comment
@ Тимста, я рада, что мое предложение сработало для вас. Благодарен также за переполнение стека. Хорошего дня. - person Miracool; 16.07.2018

Мне потребовалось время, чтобы найти решение.

Если ваш сервер отвечает правильно и проблема связана с запросом, вам следует добавить withCredentials: true к xhrFields в запросе:

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

Примечание: jQuery> = 1.5.1 требуется

person Dekel    schedule 02.03.2017
comment
Версия jquery в порядке? вы установили withCredentials: true? вы уверены, что у вас есть соответствующие заголовки? - person Dekel; 18.09.2017
comment
Да, 1withCredential: true, jquery версия: 3.2.1`. На самом деле он работает через почтальона, но не проходит через браузер Chrome. - person Mox Shah; 18.09.2017
comment
Я почти уверен, что у почтальона не должно быть проблем с CORS, потому что это не браузер и его поведение другое. Вы уверены, что у вас есть правильные и актуальные заголовки, отправляемые с сервера клиенту? Опять же - обратите внимание, что этого изменения недостаточно. Вам необходимо убедиться, что ответ сервера содержит правильные заголовки. - person Dekel; 18.09.2017
comment
Не могли бы вы сказать мне, какой заголовок ответа требуется на сервере? - person Mox Shah; 19.09.2017
comment
@MoxShah это совершенно другой вопрос и там много ресурсов :) - person Dekel; 19.09.2017

Я боролся с этой проблемой пару недель.

Самый простой, наиболее совместимый и не требующий взлома способ сделать это - вероятно, использовать JavaScript API провайдера, который не выполняет вызовы через браузер и может обрабатывать запросы Cross Origin.

Например. Facebook JavaScript API и Google JS API.

Если ваш поставщик API не является текущим и не поддерживает заголовок Cross Origin Resource Origin '*' в своем ответе и не имеет JS api (да, я говорю о вас, Yahoo), вас поразил один из трех вариантов:

  1. Использование jsonp в ваших запросах, который добавляет функцию обратного вызова к вашему URL-адресу, где вы можете обработать свой ответ. Предостережение: это изменит URL-адрес запроса, поэтому ваш сервер API должен быть оборудован для обработки? Callback = в конце URL-адреса.

  2. Отправьте запрос на свой сервер API, который является вашим контроллером и находится либо в том же домене, что и клиент, либо с включенным совместным использованием ресурсов Cross Origin, откуда вы можете проксировать запрос на сторонний сервер API.

  3. Вероятно, наиболее полезно в тех случаях, когда вы делаете запросы OAuth и вам нужно обрабатывать взаимодействие с пользователем. Ха-ха! window.open('url',"newwindowname",'_blank', 'toolbar=0,location=0,menubar=0')

person Pritam Roy    schedule 01.08.2015

Использование этого в сочетании с Laravel решило мою проблему. Просто добавьте этот заголовок в свой jquery-запрос Access-Control-Request-Headers: x-requested-with и убедитесь, что в вашем ответе на стороне сервера этот заголовок установлен Access-Control-Allow-Headers: *.

person M K    schedule 13.04.2014
comment
Нет причин добавлять заголовки CORS в запрос вручную. Браузер всегда будет добавлять заголовки CORS к запросу за вас. - person Ray Nicholus; 13.04.2014
comment
Настоящая проблема состоит в том, чтобы заставить сервер ответить правильным Access-Control-Allow-Headers и JQ, предоставив правильным Access-Control-Request-Headers (плюс все, что вы добавляете с помощью кода), ни один из которых не может быть подстановочным знаком. достаточно одного плохого заголовка, чтобы взорвать предполетную подготовку, например использование If-None-Match для условного GET, если сервер не имеет этого в списке. - person escape-llc; 08.06.2017

Это краткое изложение того, что у меня сработало:

Определите новую функцию (обернутую $.ajax для упрощения):

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

Использование:

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

Также работает с _4 _, _ 5_ и т. Д .:

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

На стороне сервера (в данном случае, когда размещен example.com) установите эти заголовки (добавлен пример кода в 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);

Это единственный известный мне способ по-настоящему кросс-доменный POST из JS.

JSONP преобразует POST в GET, который может отображать конфиденциальную информацию в журналах сервера.

person lepe    schedule 05.08.2016

По какой-то причине вопрос о запросах GET был объединен с этим, поэтому я отвечу на него здесь.

Эта простая функция будет асинхронно получать ответ HTTP-статуса от страницы с поддержкой CORS. Если вы запустите его, вы увидите, что только страница с правильными заголовками возвращает статус 200 при доступе через XMLHttpRequest - независимо от того, используется ли GET или POST. На стороне клиента ничего нельзя сделать, чтобы обойти это, кроме, возможно, использования JSONP, если вам просто нужен объект json.

Следующее можно легко изменить, чтобы получить данные, хранящиеся в объекте 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>

person Victor Stoddard    schedule 14.09.2017

У меня была точно такая же проблема, когда jquery ajax выдавал мне проблемы cors только в почтовых запросах, где запросы на получение работали нормально - я устал от всего выше без результатов. У меня были правильные заголовки на моем сервере и т. Д. Переход на использование XMLHTTPRequest вместо jquery немедленно устранил мою проблему. Независимо от того, какую версию jquery я использовал, это не исправило. Fetch также работает без проблем, если вам не нужна обратная совместимость с браузером.

        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)

Надеюсь, это поможет кому-нибудь еще с теми же проблемами.

person ozzieisaacs    schedule 18.06.2018

Если по каким-то причинам при попытке добавить заголовки или установить политику управления вы все равно ничего не добьетесь, вы можете рассмотреть возможность использования apache ProxyPass…

Например, в один <VirtualHost>, использующий SSL, добавьте две следующие директивы:

SSLProxyEngine On
ProxyPass /oauth https://remote.tld/oauth

Убедитесь, что загружены следующие модули apache (загрузите их с помощью a2enmod):

  • доверенное лицо
  • proxy_connect
  • proxy_http

Очевидно, вам придется изменить URL-адрес запросов AJAX, чтобы использовать прокси-сервер apache ...

person llange    schedule 10.03.2019

Это немного поздно для вечеринки, но я борюсь с этим пару дней. Это возможно, и ни один из ответов, которые я нашел здесь, не сработал. Это обманчиво просто. Вот вызов .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>

Вот php на стороне сервера:

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

person Steve Johnson    schedule 03.11.2016
comment
Как бы то ни было, заголовок Origin - это заголовок запроса, а не заголовок ответа. Ваш php-скрипт не должен его настраивать. - person Noodles; 25.11.2016
comment
Хммм. Это вселило мои надежды, а затем разбило их, когда я увидел, что вы делаете AJAX GET в своем коде, когда OP совершенно ясно сказал, что он пытается ИЗБЕЖАТЬ с помощью GET и хочет использовать POST. - person Steve Sauder; 26.03.2017
comment
Заголовки CORS работают одинаково независимо от используемого глагола. Мы можем вызывать все команды через $.ajax() на правильно настроенном сервере. Самое сложное - получить Access-Control-Request-Headers правильный ответ, но даже это не так уж сложно. Как отмечалось на предыдущих плакатах, это должен быть не подстановочный знак, а белый список заголовков. - person escape-llc; 08.06.2017