Запит CORS POST працює з простого JavaScript, але чому б не з jQuery?


87

Я намагаюся зробити запит на публікацію Cross Origin, і я змусив його працювати JavaScriptтак:

var request = new XMLHttpRequest();
var params = "action=something";
request.open('POST', url, true);
request.onreadystatechange = function() {if (request.readyState==4) alert("It worked!");};
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
request.setRequestHeader("Content-length", params.length);
request.setRequestHeader("Connection", "close");
request.send(params);

Але я хотів би використовувати jQuery, але я не можу змусити його працювати. Це те, що я намагаюся:

$.ajax(url, {
    type:"POST",
    dataType:"json",
    data:{action:"something"}, 
    success:function(data, textStatus, jqXHR) {alert("success");},
    error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Це призводить до Помилки. Якщо хтось знає, чому jQueryце не працює, будь ласка, повідомте нам усіх. Дякую.

(Я використовую jQuery1.5.1 та Firefox 4.0, і мій сервер відповідає належним Access-Control-Allow-Originзаголовком)


Це було рішення для мене (використовуйте XMLHttpRequest від Javascript) під час зіткнення з проблемами CORS з
Ionic

Відповіді:


73

ОНОВЛЕННЯ: Як зазначив TimK, це більше не потрібно з jquery 1.5.2. Але якщо ви хочете додати власні заголовки або дозволити використання облікових даних (ім’я користувача, пароль або файли cookie тощо), читайте далі.


Здається, я знайшов відповідь! (4 години і багато лайки пізніше)

//This does not work!!
Access-Control-Allow-Headers: *

Вам потрібно вручну вказати всі заголовки, які ви приймаєте (принаймні, це було для мене у FF 4.0 та Chrome 10.0.648.204).

Метод $ .ajax jQuery надсилає заголовок "x-request-with" для всіх міждоменних запитів (я думаю, що це єдиний міждомен).

Отже, відсутній заголовок, необхідний для відповіді на запит OPTIONS:

//no longer needed as of jquery 1.5.2
Access-Control-Allow-Headers: x-requested-with

Якщо ви передаєте будь-які не "прості" заголовки, вам потрібно буде включити їх у свій список (я надсилаю ще один):

//only need part of this for my custom header
Access-Control-Allow-Headers: x-requested-with, x-requested-by

Отже, щоб скласти все це, ось мій PHP:

// * wont work in FF w/ Allow-Credentials
//if you dont need Allow-Credentials, * seems to work
header('Access-Control-Allow-Origin: http://www.example.com');
//if you need cookies or login etc
header('Access-Control-Allow-Credentials: true');
if ($this->getRequestMethod() == 'OPTIONS')
{
  header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  header('Access-Control-Max-Age: 604800');
  //if you need special headers
  header('Access-Control-Allow-Headers: x-requested-with');
  exit(0);
}

5
Зауважте, що jQuery 1.5.2 змінив свою поведінку. Він більше не додає заголовок "X-Request-With", тому це може більше не бути проблемою. blog.jquery.com/2011/03/31/jquery-152-випущено (Помилка 8423)
Magmatic

1
@TimK, ти маєш рацію! Я не помітив, що вони випускають 1.5.2. З огляду на це, це також працює, якщо вам потрібно попередньо перевірити його. Я оновив свою відповідь.
Will Mason

Отже, я розгублений. Вам все одно довелося написати проміжний PHP-скрипт? Тож вам не потрібно турбуватися про використання Ajax тоді, так? Або мені чогось не вистачає. Чи не існує рішення лише для JavaScript?
Елізабет

1
@Elisabeth Цей метод працює лише в тому випадку, якщо ви контролюєте запитуваний пункт призначення ... це НЕ проміжний сценарій. Це верхня частина нашого PHP, про яке ми вимагали розташування. Це має більше сенсу?
Will Mason

2
Так! дякую Волі. Я думав, ти можеш контролювати все з боку клієнта, але схоже, тобі потрібен контроль обох кінців.
Елізабет

18

Інша можливість полягає в тому, що налаштування dataType: jsonзмушує JQuery відправляти Content-Type: application/jsonзаголовок. Це вважається CORS нестандартним заголовком і вимагає попереднього запиту CORS. Ось кілька речей, які потрібно спробувати:

1) Спробуйте налаштувати свій сервер для надсилання належних попередніх відповідей. Це буде у формі додаткових заголовків, як Access-Control-Allow-Methodsі Access-Control-Allow-Headers.

2) Відкиньте dataType: jsonналаштування. JQuery повинен запитувати Content-Type: application/x-www-form-urlencodedза замовчуванням, але для впевненості ви можете замінити dataType: jsonнаcontentType: 'application/x-www-form-urlencoded'


Дякую за ідеї. Я намагався не встановлювати dataType, а встановлювати його application/x-www-form-urlencodedрівним і рівним text/plain. І я спробував додати заголовок відповіді Access-Control-Allow-Methods "POST, GET, OPTIONS"Нічого не працювало.
Magmatic

Чи можете ви заглянути в консоль помилок JavaScript (або консоль Firebug) і перевірити, чи немає помилок під час запиту? Крім того, якщо ви знаєте, як користуватися Wireshark, ви можете використовувати це, щоб побачити фактичні запити HTTP, що надходять по дроту.
monsur

1
"Інша можливість полягає в тому, що встановлення dataType: json змушує JQuery надсилати заголовок Content-Type: application / json" - цього не відбувається. dataTypeвпливає на Acceptзаголовок запиту, але не на Content-Typeзаголовок запиту.
Квентін

9

Ви надсилаєте "params" у js: request.send(params);

але "дані" у jquery ". Чи визначено дані ?: data:data,

Крім того, у вас є помилка в URL-адресі:

$.ajax( {url:url,
         type:"POST",
         dataType:"json",
         data:data, 
         success:function(data, textStatus, jqXHR) {alert("success");},
         error: function(jqXHR, textStatus, errorThrown) {alert("failure");}
});

Ви змішуєте синтаксис із таким для $ .post


Оновлення : Я гуглив на основі відповіді монсура, і виявив, що вам потрібно додати Access-Control-Allow-Headers: Content-Type(нижче - повний абзац)

http://metajack.im/2010/01/19/crossdomain-ajax-for-xmpp-http-binding-made-easy/

Як працює CORS

CORS працює дуже подібно до файлу crossdomain.xml Flash. В основному браузер надсилає міждоменний запит службі, встановлюючи HTTP-заголовок Origin на сервер, що запитує. Послуга включає кілька заголовків, таких як Access-Control-Allow-Origin, щоб вказати, чи дозволено такий запит.

Для менеджерів з’єднань BOSH достатньо вказати, що дозволено всі джерела, встановивши значення Access-Control-Allow-Origin на *. Заголовок Content-Type також повинен бути в білому списку в заголовку Access-Control-Allow-Headers.

Нарешті, для певних типів запитів, включаючи запити менеджера з’єднань BOSH, перевірка дозволів буде попередньо перевірена. Браузер зробить запит OPTIONS і очікує повернення деяких заголовків HTTP, які вказують, які джерела дозволено, які методи дозволено і як довго триватиме ця авторизація. Наприклад, ось те, що патчі для Пенджабу та ejabberd я повернув для ВАРІАНТІВ:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type 
Access-Control-Max-Age: 86400

1
Вибачте. Так. var data = {action:"something"}
Magmatic

Ви можете порівняти синтаксис обох функцій тут: api.jquery.com/jQuery.post
Aleadam

Я просто спробував це зробити з URL-адресою в налаштуваннях, але така ж проблема. Функція .ajax може прийняти його в будь-який спосіб.
Magmatic

У мене вже було два таких заголовка. Я додав інші два. Все ще "невдача" з jQuery. Звичайний javascript все ще працює.
Magmatic

Останнє, що я можу придумати, - це використовувати api.jquery.com/jQuery.ajaxSetup для встановлення jQuery.ajaxSetup({'beforeSend': function(xhr) {xhr.setRequestHeader(string, string)}})та відтворення різних відправлених заголовків (приклад для рейок тут: railscasts.com/episodes/136-jquery )
Алеадам,

1

Корди змінюють метод запиту до того, як це буде зроблено, з POST на OPTIONS, отже, дані вашого повідомлення не будуть надіслані. Спосіб роботи з цією проблемою cors - це виконання запиту за допомогою ajax, який не підтримує метод OPTIONS. приклад коду:

        $.ajax({
            type: "POST",
            crossdomain: true,
            url: "http://localhost:1415/anything",
            dataType: "json",
            data: JSON.stringify({
                anydata1: "any1",
                anydata2: "any2",
            }),
            success: function (result) {
                console.log(result)
            },
            error: function (xhr, status, err) {
                console.error(xhr, status, err);
            }
        });

з цими заголовками на сервері c #:

                    if (request.HttpMethod == "OPTIONS")
                    {
                          response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
                          response.AddHeader("Access-Control-Allow-Methods", "GET, POST");
                          response.AddHeader("Access-Control-Max-Age", "1728000");
                    }
                    response.AppendHeader("Access-Control-Allow-Origin", "*");

-2

Змініть свій Jquery наступним чином:

$.ajax({
            url: someurl,
            contentType: 'application/json',
            data: JSONObject,
            headers: { 'Access-Control-Allow-Origin': '*' }, //add this line
            dataType: 'json',
            type: 'POST',                
            success: function (Data) {....}
});

Чому я хочу зробити мої кали Ajax синхронними !?
Радко

contentType: 'application/json', data: JSONObject,- Сервер не очікує JSON, тому надсилання JSON не має сенсу. Також немає такого поняття, як JSON-об'єкт .
Квентін

1
headers: { 'Access-Control-Allow-Origin': '*' }, //add this line- Ніколи цього не роби. Access-Control-Allow-Originє заголовком відповіді , а не заголовком запиту. У кращому випадку це нічого не дасть. У гіршому випадку він перетворить запит із простого запиту на попередньо розроблений запит, що ускладнює роботу з сервером.
Квентін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.