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 не враховує номери портів при визначенні того, чи є запит перехресного походження.
Рей Ніколус

@KevinB: Наша служба REST використовує різні запити, роблячи різні дії за методом http. Переключення всього на GET не є коректним виправленням. Крім того, згідно з відповіддю Темного Сокола, це все одно не допоможе, оскільки у запитах є X-UserName та інші власні заголовки.
Корі Огберн

це не змінює того факту, що якщо ви хочете зробити запит перехресного походження, ви повинні дотримуватися всіх правил, застосовних до запитів перехресного походження, щоб він працював належним чином. запити перехресного походження зазвичай включають запит OPTIONS. Поводьтеся належним чином, і проблема піде. Єдиний інший спосіб вирішити це (не змінюючи api) - це мати сценарій на тому ж сервері, що і основна сторінка, який взаємодіє з api, використовуючи код на стороні сервера.
Кевін Б

Відповіді:


136

Chrome попередньо переглядає запит на пошук заголовків CORS . Якщо запит прийнятний, він надсилатиме реальний запит. Якщо ви робите цей крос-домен, вам просто доведеться зіткнутися з ним або ще знайти спосіб зробити запит немеждоменним. Ось чому помилка jQuery була закрита як виправлення. Це за дизайном.

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

  • Він використовує інші методи, ніж GET, HEAD або POST. Крім того, якщо POST використовується для надсилання даних запиту із типом вмісту, відмінним від application / x-www-form-urlencoded, multipart / data-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, але будьте обережні, хаос ховається. Ми дійсно не можемо зробити більше, щоб допомогти вам.


1
Наша структура системи - це те, що я не можу змінити. Використання іншого порту - це вимога нашої архітектури. Я отримую ту саму політику походження, але вважаю, що впровадженого нами КОРС було достатньо. Мабуть, ні.
Corey Ogburn

2
Якщо ваш сервер повертає відповіді JSON, ви можете вивчити метод JSONP, просто відповідально використовуйте його.
jgitter

1
Мені не хочеться сперечатися з вами, але JSONP використовує теги скриптів, щоб перетягувати дані з іншого домену, а потім надсилає результат функції зворотного виклику. Набагато складніше, якщо результат не json.
jgitter

1
Ні, це не набагато складніше. Насправді відповідь не повинна бути дійсною JSON ні в якому разі. Замість цього сервер повинен повертати що - щось на зразок цього: callbackfunc(somedata). Як бачите, це не дійсний JSON. І, somedataможе бути рядок або число, або все, що ви хочете, щоб це було.
Рей Ніколус

1
Я використовую Postman, і методи запиту надсилаються правильно (наприклад, "PUT", "DELETE" тощо). Але коли я намагаюся зробити це з мого коду, він завжди надсилає їх за допомогою методу "ВАРІАНТИ". Я поняття не маю, як поштальон здатний це зробити.
ErwinGO

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 будуть в одному домені.

Я сподіваюся, що це допомагає!


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
Чи можете ви додати трохи більше інформації? Ваша відповідь виглядає як коментар. :)
Бадакадабра

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" працювала на відмінно.


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

typeType: 'текст / звичайна; charset = utf-8 ', або просто contentType:' текст / звичайний ', працює для мене! З повагою !!


Що це взагалі пов'язане з питанням?
Корі Огберн

Привіт, я думаю, що це вирішить проблему в заголовку, за допомогою цього типу вмісту ви передаєте метод OPTIONS. З повагою
Девід Лопес

ContentType не має нічого спільного з методом.
Корі Огберн

Я знаю, що ви говорите, але спробуйте. залежно від браузера, який ваш тип вмісту може вплинути на ваш запит і змінити ваш метод!
Девід Лопес
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.