Чому я отримую запит OPTIONS замість GET-запиту?


288
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js" type="text/javascript"></script>
<script>
$.get("http://example.com/", function(data) {
     alert(data);
});
</script>

вона робить запит OPTIONS на цю URL-адресу, і тоді зворотний виклик ніколи не викликається нічим.

Якщо це не міждоменний, він працює чудово.

Чи не повинен jQuery просто робити дзвінок із <script>вузлом, а потім робити зворотний виклик, коли він завантажений? Я розумію, що я не зможу отримати результат (оскільки це крос-домен), але це нормально; Я просто хочу, щоб дзвінок пройшов. Це помилка, чи я щось роблю не так?


2
Може бути, крос-домен. Наприклад, якщо у вас є файл Файл: // PATH_TO_WEBSITE замість того, щоб використовувати localhost / WEBSITE_LINK
James111

Відповіді:


262

За даними MDN ,

Попередньо попередні запити

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

  • Він використовує інші методи, ніж GET або POST. Крім того, якщо POST використовується для надсилання даних запиту із типом контенту, відмінним від application / x-www-form-urlencoded, multipart / data-data, або text / plain, наприклад, якщо POST-запит надсилає на сервер корисну навантаження XML використовуючи application / xml або text / xml, тоді запит попередньо просвічується.
  • Він встановлює власні заголовки у запиті (наприклад, у запиті використовується заголовок, наприклад X-PINGOTHER)

43
це вирішило нашу проблему, перехід від "application / json" до "text / plain" зупинив жахливий запит на параметри
Keeno

10
чого я не розумію, чому браузер запитує метод OPTIONS, щоб перевірити, чи справді запит безпечно відправити. але в якому сенсі? я маю на увазі, сервер також може поставити обмеження з певними заголовками відповідей, так для чого це потрібно?
hardik

11
@hardik Пам’ятайте, що додаючи CORS, ви потенційно приймаєте запити від будь-кого, в якому вони можуть маніпулювати даними на вашому сервері за допомогою запитів (POST, PUT, DELETE тощо). У таких ситуаціях, як, наприклад, під час використання користувальницьких заголовків, браузер просто спочатку перевіряє з сервером, що сервер готовий прийняти запит, перш ніж надсилати його, оскільки надсилання непроханих запитів на сервер може бути справді небезпечним для ваших даних, а також, що точка в браузері, що надсилає потенційно великі корисні навантаження, якщо сервер не бажає їх приймати, отже, перевіряйте ПАРАМЕТРИ перед польотом.
davidnknight

6
@davidnknight, якщо надсилання ваших даних на сервер може бути небезпечним, тобто сервер може бути порушений, то, звичайно, зловмисний сервер відповість на ваш запит ВАРІАНТІВ "Звичайно, надсилайте їх у всьому!". Як це безпека? (чесне запитання)
Метт

3
"Запити перед перельотом не є предметом безпеки. Швидше, це не річ, що не змінюється." - Дивіться відповідь на те, що мотивує
подання заявок на попереднє поле


9

Якщо ви намагаєтесь POST

Обов’язково JSON.stringifyвведіть дані форми та надішліть як text/plain.

<form id="my-form" onSubmit="return postMyFormData();">
    <input type="text" name="name" placeholder="Your Name" required>
    <input type="email" name="email" placeholder="Your Email" required>
    <input type="submit" value="Submit My Form">
</form>

function postMyFormData() {

    var formData = $('#my-form').serializeArray();
    formData = formData.reduce(function(obj, item) {
        obj[item.name] = item.value;
        return obj;
    }, {});
    formData = JSON.stringify(formData);

    $.ajax({
        type: "POST",
        url: "https://website.com/path",
        data: formData,
        success: function() { ... },
        dataType: "text",
        contentType : "text/plain"
    });
}

2

Я не вірю, що jQuery природно зробить запит JSONP, коли йому буде надана така URL-адреса. Однак він виконає запит JSONP, коли ви розповісте, який аргумент використовувати для зворотного дзвінка:

$.get("http://metaward.com/import/http://metaward.com/u/ptarjan?jsoncallback=?", function(data) {
     alert(data);
});

Цілком належить до сценарію прийому використовувати цей аргумент (який не повинен називатися "jsoncallback"), тому в цьому випадку функція ніколи не буде викликана. Але, оскільки ви заявили, що просто хочете виконати скрипт на metaward.com, це зробило б це.


Чи мій зворотний виклик все ще отримає сповіщення про те, що елемент сценарію повністю завантажений? Я просто хочу переконатися, що оновлення відбулося, перш ніж запитати API для нього.
Пол Тарджан

Ви отримаєте, якщо приймаючий скрипт підтримує JSONP, і буде готовий зателефонувати до визначеної вами функції. Якщо сценарій не робить нічого, крім генерування блоку даних JSON без жодної іншої поведінки, ви не зможете сказати, коли це буде завантажено. Якщо важливо сказати, коли закінчується завантаження, ви можете розглянути можливість застосування сценарію на власному сервері, який виконує функції проксі.
VoteyDisciple

1

Насправді, міждоменні запити AJAX (XMLHttp) заборонені з міркувань безпеки (подумайте про отримання "обмеженої" веб-сторінки з боку клієнта та відправлення її назад на сервер - це буде проблемою безпеки).

Єдине рішення - зворотні дзвінки. Це: створення нового об’єкта скрипту та вказівка ​​src на кінцевий бік JavaScript, який є зворотним викликом зі значеннями JSON (myFunction ({дані}), myFunction - це функція, яка щось робить із даними (наприклад, зберігаючи їх у змінній).


1
правильно, але я можу завантажити його в <script src = ""> або <img src = ""> і браузер із задоволенням вдарить по ньому. Я просто хочу знати, коли він завантажений повністю, щоб я міг запитати про результат імпорту.
Пол Тарджан

1

Просто змініть "application / json" на "text / plain" і не забудьте JSON.stringify (запит):

var request = {Company: sapws.dbName, UserName: username, Password: userpass};
    console.log(request);
    $.ajax({
        type: "POST",
        url: this.wsUrl + "/Login",
        contentType: "text/plain",
        data: JSON.stringify(request),

        crossDomain: true,
    });

1

У мене була така ж проблема. Моє виправлення було додати заголовки до мого скрипту PHP, які присутні лише у середовищі розробників.

Це дозволяє запити між доменами:

header("Access-Control-Allow-Origin: *");

Це говорить про запит перед передпольотом, що клієнт може надсилати будь-які заголовки, які він хоче:

header("Access-Control-Allow-Headers: *");

Таким чином, немає необхідності змінювати запит.

Якщо у вашій базі даних розробників є чутливі дані, які потенційно можуть просочитися, ви можете подумати над цим два рази.


1

У моєму випадку проблема не була пов'язана з CORS, оскільки я видав jQuery POST на той же веб-сервер. Дані були JSON, але я опустив параметр dataType: 'json'.

У мене не було (ні я не додавав) параметра contentType, як показано у відповіді Девіда Лопеса вище.


0

Схоже, Firefox і Opera (тестовані також на mac) не люблять перехресну доменність цього (але Safari це чудово).

Можливо, вам доведеться зателефонувати до коду локального сервера, щоб згортати віддалену сторінку.


0

Я зміг це виправити за допомогою наступних заголовків

Access-Control-Allow-Origin
Access-Control-Allow-Headers
Access-Control-Allow-Credentials
Access-Control-Allow-Methods

Якщо ви перебуваєте на Nodejs, ось код, який ви можете скопіювати / вставити.

app.use((req, res, next) => {
  res.header('Access-Control-Allow-Origin','*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, PATCH');
  next();
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.