AJAX в Chrome отправляет ОПЦИИ вместо GET/POST/PUT/DELETE?

Я работаю над внутренним веб-приложением на работе. В IE10 запросы работают нормально, но в Chrome все AJAX-запросы (которых их много) отправляются с использованием OPTIONS вместо любого определенного мной метода. Технически мои запросы являются "междоменными". Сайт обслуживается на localhost:6120, а служба, к которой я обращаюсь к AJAX-запросам, работает на 57124. Эта закрытая ошибка jquery определяет проблему, но не решает ее.

Что я могу сделать, чтобы использовать правильный метод http в запросах ajax?

Редактировать:

Это в документе загрузки каждой страницы:

jQuery.support.cors = true;

И каждый AJAX построен аналогично:

var url = 'http://localhost:57124/My/Rest/Call';
$.ajax({
    url: url,
    dataType: "json",
    data: json,
    async: true,
    cache: false,
    timeout: 30000,
    headers: { "x-li-format": "json", "X-UserName": userName },
    success: function (data) {
        // my success stuff
    },
    error: function (request, status, error) {
        // my error stuff
    },
    type: "POST"
});

9 ответов

Решение

Chrome выполняет предварительный поиск запроса на поиск заголовков CORS. Если запрос приемлем, он отправит реальный запрос. Если вы делаете этот междоменный домен, вам просто придется иметь дело с ним или иначе найти способ сделать запрос не междоменным. Вот почему ошибка jQuery была закрыта как не исправленная. Это по замыслу.

В отличие от простых запросов (обсужденных выше), "предварительно выданные" запросы сначала отправляют HTTP-запрос методом OPTIONS ресурсу в другом домене, чтобы определить, безопасен ли фактический запрос для отправки. Межсайтовые запросы предварительно просматриваются следующим образом, так как они могут иметь значение для пользовательских данных. В частности, запрос предварительно просвечивается, если:

  • Он использует методы, отличные от GET, HEAD или POST. Кроме того, если POST используется для отправки данных запроса с Content-Type, отличным от application/x-www-form-urlencoded, multipart/form-data или text/plain, например, если запрос POST отправляет полезную нагрузку XML на сервер используя application/xml или text/xml, запрос предварительно просвечивается.
  • Он устанавливает пользовательские заголовки в запросе (например, запрос использует заголовок, такой как X-PINGOTHER)

Исходя из того факта, что запрос не отправляется на порт 80/443 по умолчанию, этот Ajax-вызов автоматически считается запросом ресурса разных источников (CORS), что означает, что запрос автоматически выдает запрос OPTIONS, который проверяет наличие Заголовки CORS на стороне сервера / сервлета.

Это происходит, даже если вы установили

crossOrigin: false;

или даже если вы пропустите это.

Причина в том, что localhost != localhost:57124, Попробуйте отправить его только localhost без порта - это не удастся, потому что запрошенная цель не будет достигнута, однако обратите внимание, что если доменные имена равны, запрос отправляется без запроса OPTIONS до POST.

Я согласен с Кевином Б., в сообщении об ошибке все сказано. Похоже, вы пытаетесь совершать междоменные вызовы AJAX. Если вы не знакомы с той же политикой происхождения, вы можете начать здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Same_origin_policy_for_JavaScript.

Если это не предназначено для междоменного вызова ajax, попробуйте сделать ваш целевой URL относительным и посмотреть, исчезнет ли проблема. Если вы действительно отчаянно ищите JSONP, но будьте осторожны, хаос скрывается. На самом деле мы мало что можем сделать, чтобы помочь вам.

В моем случае я вызываю API, размещенный на AWS (API Gateway). Ошибка произошла, когда я попытался вызвать API из домена, отличного от собственного домена API. Поскольку я владелец API, я включил CORS для тестовой среды, как описано в документации Amazon.

В производстве эта ошибка не произойдет, так как запрос и API будут находиться в одном домене.

Я надеюсь, что это помогает!

Если это возможно, передайте параметры через обычный GET/POST с другим именем, и пусть ваш серверный код обрабатывает его.

У меня была похожая проблема с моим собственным прокси, чтобы обойти CORS, и я получил ту же ошибку POST->OPTION в Chrome. Это было Authorization заголовок в моем случае ("x-li-format" а также "X-UserName" здесь, в вашем случае.) Я в конечном итоге передать его в фиктивном формате (например, AuthorizatinJack в GET), и я изменил код для моего прокси, чтобы превратить его в заголовок при совершении звонка по назначению. Вот это в PHP:

if (isset($_GET['AuthorizationJack'])) {
    $request_headers[] = "Authorization: Basic ".$_GET['AuthorizationJack'];
}

Я столкнулся с очень похожей проблемой. Я потратил почти полдня, чтобы понять, почему все работает правильно в Firefox и не работает в Chrome. В моем случае это было из-за дублированных (или, возможно, опечаток) полей в заголовке моего запроса.

"предварительно выданные" запросы сначала отправляют HTTP-запрос методом OPTIONS ресурсу в другом домене, чтобы определить, является ли фактический запрос безопасным для отправки. Межсайтовые запросы

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Как ответил @Dark Falcon, я просто с этим справился.

В моем случае я использую сервер node.js и создаю сеанс, если он не существует. Так как метод OPTIONS не содержит подробностей сеанса, он в конечном итоге создал новый сеанс для каждого запроса метода POST.

Так что в моей подпрограмме приложения create-session-if-not-there я просто добавил проверку, чтобы проверить, является ли метод OPTIONSи, если это так, просто пропустите часть создания сеанса:

    app.use(function(req, res, next) {
        if (req.method !== "OPTIONS") {
            if (req.session && req.session.id) {
                 // Session exists
                 next();
            }else{
                 // Create session
                 next();
          }
        } else {
           // If request method is OPTIONS, just skip this part and move to the next method.
           next(); 
        }
    }

Рассмотрите возможность использования Axios

axios.get( url,
{ headers: {"Content-Type": "application/json"} } ).then( res => {

  if(res.data.error) {

  } else { 
    doAnything( res.data )
  }

}).catch(function (error) {
   doAnythingError(error)
});

У меня была эта проблема с использованием fetch и Axios работал отлично.

Используйте fetch вместо XHR, тогда запрос не будет предварительно подсвечен, даже если он является кросс-доменным.

 $.ajax({
            url: '###',
            contentType: 'text/plain; charset=utf-8',
            async: false,
            xhrFields: {
                withCredentials: true,
                crossDomain: true,
                Authorization: "Bearer ...."
            },

            method: 'POST',

            data: JSON.stringify( request ),
            success: function (data) {
                console.log(data);
            }
        });

contentType: 'текст / простой; charset=utf-8'или просто contentType: 'text/plain'у меня работает! С уважением!!

Другие вопросы по тегам