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

107

Я работаю над внутренним веб-приложением на работе. В 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"
});
Кори Огберн
источник
2
Последний комментарий в том отчете об ошибке объясняет это довольно хорошо ...
Кевин Б.
1
Это перевернуло мое мнение, потому что все, что я делаю, настолько ванильное (и мой код похож на код ошибки jquery). Кроме того, это не оправдание, чтобы не включить его. BRB, берем пример кода.
Кори Огберн
3
Обратите внимание, что IE не учитывает номера портов при определении того, является ли запрос перекрестным источником.
Ray Nicholus
@KevinB: Наша служба REST использует различные запросы, выполняя разные действия на основе метода http. Переключение всего на GET - недопустимое решение. Кроме того, согласно ответу Dark Falcon, это все равно не поможет, потому что в запросах есть X-UserName и другие настраиваемые заголовки.
Кори Огберн
это не меняет того факта, что, если вы хотите сделать запрос между источниками, вы должны соблюдать все правила, применимые к запросам из разных источников, чтобы он работал правильно. Запросы между источниками обычно включают запрос OPTIONS. Обращайтесь с ним правильно, и проблема исчезнет. Единственный другой способ решить эту проблему (без изменения api) - иметь сценарий на том же сервере, что и основная страница, который взаимодействует с api с использованием серверного кода.
Kevin B

Ответы:

136

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)
Темный сокол
источник
20
Пользовательские заголовки. Вероятно, это то, что вызывает предварительные вызовы OPTIONS.
Кори Огберн
18

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

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

crossOrigin: false;

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

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

Выбывать
источник
3

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

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

jgitter
источник
1
Я не могу изменить структуру нашей системы. Использование другого порта - требование нашей архитектуры. У меня такая же политика происхождения, но я подумал, что реализованной нами CORS было достаточно. Очевидно нет.
Кори Огберн,
2
Если ваш сервер возвращает ответы JSON, вы можете изучить метод JSONP, просто используйте его ответственно.
jgitter
1
Я не собираюсь спорить с вами, но JSONP использует теги сценария для извлечения данных из другого домена, а затем отправляет результат в функцию обратного вызова. Намного сложнее, если результат не json.
jgitter
1
Нет, это не намного сложнее. На самом деле ответ не должен быть действительным JSON в любом случае. Вместо этого сервер должен возвращать что - то вроде этого: callbackfunc(somedata). Как видите, это недопустимый JSON. И somedataможет быть строкой, числом или чем угодно.
Ray Nicholus
1
Я использую Postman, и там методы запроса отправляются правильно (например, «PUT», «DELETE» и т. Д.). Но когда я пытаюсь сделать это из своего кода, он всегда отправляет их с методом запроса OPTIONS. Понятия не имею, как Почтальон это умеет.
ErwinGO 06
1

Если возможно, передайте параметры через обычный 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'];
}
Помощь в
источник
1

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

В процессе производства этой ошибки не будет, поскольку запрос и api будут в одном домене.

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

Gbonesso
источник
0

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

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

Итак, в моей подпрограмме приложения для создания-сеанса-если-не-существует я просто добавил проверку, чтобы увидеть, есть ли метод 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(); 
        }
    }
Махеш
источник
0

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

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

Норулла
источник
1
Не могли бы вы добавить немного дополнительной информации? Ваш ответ выглядит как комментарий. :)
Badacadabra 08
0

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

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 отлично работали.

Evhz
источник
5
Axios также использует первые ОПЦИИ
Skylin R
0

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

Андрей Татомир
источник
0

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

Фэй Сун
источник
-1
 $.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 'у меня работает! С уважением!!

Дэвид Лопес
источник
Какое это вообще имеет отношение к вопросу?
Кори Огберн
Привет, я думаю, это решит проблему в заголовке, с этим типом контента вы передаете метод OPTIONS. С уважением
Дэвид Лопес
ContentType не имеет ничего общего с методом.
Кори Огберн
Я знаю, что вы говорите, но попробуйте. в зависимости от браузера, ваш тип контента может повлиять на ваш запрос и изменить ваш метод!
Дэвид Лопес