Как заставить работать пост-запрос совместного использования ресурсов между источниками (CORS) - PullRequest
187 голосов
/ 22 апреля 2011

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

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

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

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

Ответы [ 11 ]

141 голосов
/ 22 апреля 2011

Я наконец наткнулся на эту ссылку " Запрос 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 
62 голосов
/ 06 декабря 2013

ЗАПРОС:

 $.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
12 голосов
/ 02 марта 2017

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

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

9 голосов
/ 01 августа 2015

Ну, я боролся с этой проблемой в течение нескольких недель.

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

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

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

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

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

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

4 голосов
/ 13 апреля 2018

Я решил собственную проблему при использовании 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":"*"
      }

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

4 голосов
/ 13 апреля 2014

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

1 голос
/ 18 июня 2018

У меня была точно такая же проблема, когда jquery ajax только давал мне проблемы с корсом при почтовых запросах, где запросы get работали нормально - я устал все выше без результатов.У меня были правильные заголовки на моем сервере и т. Д. Переключение на использование 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)

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

1 голос
/ 15 сентября 2017

По какой-то причине вопрос о запросах 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>
1 голос
/ 05 августа 2016

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

Определение новой функции (для упрощения $.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) {
           ...
      }
});

Также работает с .done, .fail и т. Д .:

$.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, который может отображать конфиденциальную информацию в журналах сервера.

0 голосов
/ 10 марта 2019

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

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

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

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

  • proxy
  • proxy_connect
  • proxy_http

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

...