jQuery $.ajax(), $.post отправляет "OPTIONS" как REQUEST_METHOD в Firefox

Возникли проблемы с тем, что я считал относительно простым плагином jQuery...

Плагин должен извлекать данные из php-скрипта через ajax, чтобы добавить параметры в <select>, Ajax-запрос довольно общий:

$.ajax({
  url: o.url,
  type: 'post',
  contentType: "application/x-www-form-urlencoded",
  data: '{"method":"getStates", "program":"EXPLORE"}',
  success: function (data, status) {
    console.log("Success!!");
    console.log(data);
    console.log(status);
  },
  error: function (xhr, desc, err) {
    console.log(xhr);
    console.log("Desc: " + desc + "\nErr:" + err);
  }
});

В Safari это работает нормально. В Firefox 3.5 REQUEST_TYPE на сервере всегда 'OPTIONS', а данные $_POST не отображаются. Apache регистрирует запрос как тип "OPTIONS":

::1 - - [08/Jul/2009:11:43:27 -0500] "OPTIONS sitecodes.php HTTP/1.1" 200 46

Почему этот вызов ajax работает в Safari, но не в Firefox, и как мне это исправить для Firefox?

Заголовки ответа
Дата: среда, 08 июля 2009 21:22:17 GMT
Сервер:Apache/2.0.59 (Unix) PHP/5.2.6 DAV/2
X-Powered-By: PHP/5.2.6
Контент-длина 46
Keep-Alive  timeout=15, max=100
Keep-Alive соединения
Content-Type    text/html

Заголовки запроса
Форма заказа хоста:8888
Пользовательский агент Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1) Gecko/20090624 Firefox/3.5
Принять текст /html,application/xhtml+xml,application/xml;q=0,9,*/*;q=0,8
Accept-Language en-us,en;q=0,5
Принять кодировку gzip,deflate
Accept-Charset  ISO-8859-1,utf-8;q=0,7,*;q=0,7
Keep-Alive  300
Поддержание связи
Происхождение http://ux.inetu.act.org
Access-Control-Request-Метод POST
Заголовки-Access-Control-Request-x

Вот изображение выхода Firebug:

23 ответа

Решение

Причиной ошибки является та же политика происхождения. Это только позволяет вам делать запросы XMLHTTP к вашему собственному домену. Посмотрите, можете ли вы использовать обратный вызов JSONP:

$.getJSON( 'http://<url>/api.php?callback=?', function ( data ) { alert ( data ); } );

Я использовал следующий код на стороне Django, чтобы интерпретировать запрос OPTIONS и установить требуемые заголовки Access-Control. После этого мои междоменные запросы от Firefox начали работать. Как уже было сказано, браузер сначала отправляет запрос OPTIONS, а затем сразу после этого отправляет запрос POST/GET.

def send_data(request):
    if request.method == "OPTIONS": 
        response = HttpResponse()
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'POST, GET, OPTIONS'
        response['Access-Control-Max-Age'] = 1000
        # note that '*' is not valid for Access-Control-Allow-Headers
        response['Access-Control-Allow-Headers'] = 'origin, x-csrftoken, content-type, accept'
        return response
    if request.method == "POST":
        # ... 

Изменить: кажется, что по крайней мере в некоторых случаях вам также необходимо добавить те же заголовки Access-Control к фактическому ответу. Это может немного сбивать с толку, так как запрос кажется успешным, но Firefox не передает содержимое ответа в Javascript.

В этой статье центра разработчиков Mozilla описаны различные сценарии междоменных запросов. Кажется, в статье указывается, что POST-запрос с типом содержимого "application/x-www-form-urlencoded" следует отправлять как "простой запрос" (без запроса "preflight" OPTIONS). Однако я обнаружил, что Firefox отправил запрос OPTIONS, хотя мой POST был отправлен с этим типом контента.

Я смог сделать эту работу, создав на сервере обработчик запросов опций, который установил для заголовка ответа "Access-Control-Allow-Origin" значение "*". Вы можете быть более строгими, установив для него что-то конкретное, например " http://someurl.com/". Кроме того, я читал, что, предположительно, вы можете указать разделенный запятыми список нескольких источников, но я не мог заставить это работать.

Как только Firefox получает ответ на запрос OPTIONS с приемлемым значением "Access-Control-Allow-Origin", он отправляет запрос POST.

Я исправил эту проблему, используя полностью основанное на Apache решение. В моем vhost / htaccess я поставил следующий блок:

# enable cross domain access control
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS"

# force apache to return 200 without executing my scripts
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule .* / [R=200,L]

Вам может не понадобиться последняя часть, в зависимости от того, что происходит, когда Apache выполняет ваш целевой скрипт. Кредит идет к дружественному народу ServerFault для последней части.

Этот PHP в верхней части отвечающего скрипта, кажется, работает. (С Firefox 3.6.11. Я еще не провел много испытаний.)

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
if(array_key_exists('HTTP_ACCESS_CONTROL_REQUEST_HEADERS', $_SERVER)) {
    header('Access-Control-Allow-Headers: '
           . $_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
} else {
    header('Access-Control-Allow-Headers: *');
}

if("OPTIONS" == $_SERVER['REQUEST_METHOD']) {
    exit(0);
}

Culprit - это предполетный запрос с использованием метода OPTIONS

Для методов HTTP-запроса, которые могут вызывать побочные эффекты для пользовательских данных (в частности, для HTTP-методов, отличных от GET, или для использования POST с определенными типами MIME), спецификация предписывает браузерам "предварительно проверять" запрос, запрашивая поддерживаемые методы из сервер с методом запроса HTTP OPTIONS, а затем, после "одобрения" от сервера, отправляет фактический запрос с фактическим методом HTTP-запроса.

Веб-спецификация относится к: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Я решил проблему, добавив следующие строки в Nginx conf.

    location / {
               if ($request_method = OPTIONS ) {
                   add_header Access-Control-Allow-Origin  "*";
                   add_header Access-Control-Allow-Methods "POST, GET, PUT, UPDATE, DELETE, OPTIONS";
                   add_header Access-Control-Allow-Headers "Authorization";
                   add_header Access-Control-Allow-Credentials  "true";
                   add_header Content-Length 0;
                   add_header Content-Type text/plain;
                   return 200;
               }
    location ~ ^/(xxxx)$ {
                if ($request_method = OPTIONS) {
                    rewrite ^(.*)$ / last;
                }
    }

У меня была такая же проблема с отправкой запросов на карты Google, и решение довольно просто с jQuery 1.5 - для использования dataType dataType: "jsonp"

У нас была такая проблема с ASP.Net. Наш IIS возвращал внутреннюю ошибку сервера при попытке выполнить jQuery $.post чтобы получить некоторое содержание HTML из-за PageHandlerFactory было запрещено отвечать только GET,HEAD,POST,DEBUG Глаголы. Таким образом, вы можете изменить это ограничение, добавив глагол "OPTIONS" в список или выбрав "All Verbs"

Вы можете изменить это в диспетчере IIS, выбрав свой веб-сайт, затем выбрав "Сопоставления обработчиков", дважды щелкнув в вашем PageHandlerFactory для файлов *.apx, как вам нужно (мы используем интегрированный пул приложений со структурой 4.0). Нажмите Запрос ограничений, затем перейдите на вкладку Глаголы и примените ваши изменения.

Теперь наш $.post запрос работает как положено:)

Я просматривал источник 1.3.2, когда при использовании JSONP запрос выполнялся путем динамического построения элемента SCRIPT, который проходит мимо политики браузера Same-domain. Естественно, вы не можете сделать POST-запрос, используя элемент SCRIPT, браузер получит результат, используя GET.

Поскольку вы запрашиваете вызов JSONP, элемент SCRIPT не генерируется, поскольку он делает это только тогда, когда для вызова Тип AJAX установлено значение GET.

http://dev.jquery.com/ticket/4690

Мне кажется что если o.url = 'index.php' и этот файл существует в порядке и возвращает сообщение об успехе в консоли. Он возвращает ошибку, если я использую URL:http://www.google.com

Если вы выполняете почтовый запрос, почему бы не использовать метод $.post напрямую:

$.post("test.php", { func: "getNameAndTime" },
    function(data){
        alert(data.name); // John
        console.log(data.time); //  2pm
    }, "json");

Это намного проще.

Проверьте, если ваша форма action URL включает в себя www часть домена, а открытая исходная страница просматривается без www,

Обычно делается для канонических URL.

Я боролся в течение нескольких часов, прежде чем наткнулся на эту статью и нашел намек на Cross Domain.

Решение этой проблемы:

  1. использовать dataType: json
  2. добавлять &callback=? на ваш URL

это сработало при вызове Facebook API и Firefox. Firebug использует GET вместо OPTIONS с вышеуказанными условиями (оба).

Я опубликовал четкий пример того, как решить эту проблему, если вы управляете кодом сервера домена, на который вы размещаете сообщение. Этот ответ затрагивается в этой теме, но это более четко объясняет его IMO.

Как отправить междоменный запрос POST через JavaScript?

Другая возможность обойти проблему - использовать прокси-скрипт. Этот метод описан, например, здесь

У меня была похожая проблема при попытке использовать API Facebook.

Единственный contentType, который не отправлял запрос Preflighted, казался просто text / plain... а не остальными параметрами, упомянутыми здесь в mozilla

  • Почему это единственный браузер, который делает это?
  • Почему Facebook не знает и не принимает предварительный запрос?

К вашему сведению: вышеупомянутый документ Moz предлагает, что заголовки X-Lori должны инициировать предварительный запрос... это не так.

У меня уже есть этот код хорошо обрабатывает мою ситуацию cors в php:

header( 'Access-Control-Allow-Origin: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Headers: '.CMSConfig::ALLOW_DOMAIN );
header( 'Access-Control-Allow-Credentials: true' );

И он работал нормально локально и удаленно, но не для загрузки, когда удаленно.

Что-то случилось с apache/php ИЛИ моим кодом, я не стал искать его, когда вы запрашиваете OPTIONS, он возвращает мой заголовок с правилами cors, но с результатом 302. Поэтому мой браузер не распознает как приемлемую ситуацию.

Что я сделал, основываясь на ответе @Mark McDonald, просто поместил этот код после моего заголовка:

if( $_SERVER['REQUEST_METHOD'] === 'OPTIONS' )
{
    header("HTTP/1.1 202 Accepted");
    exit;
}

Теперь при запросе OPTIONS он просто отправит заголовок и 202 результата.

Попробуйте добавить следующее:

dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),  
 function test_success(page,name,id,divname,str)
{ 
 var dropdownIndex = document.getElementById(name).selectedIndex;
 var dropdownValue = document.getElementById(name)[dropdownIndex].value;
 var params='&'+id+'='+dropdownValue+'&'+str;
 //makerequest_sp(url, params, divid1);

 $.ajax({
    url: page,
    type: "post",
    data: params,
    // callback handler that will be called on success
    success: function(response, textStatus, jqXHR){
        // log a message to the console
        document.getElementById(divname).innerHTML = response;

        var retname = 'n_district';
        var dropdownIndex = document.getElementById(retname).selectedIndex;
        var dropdownValue = document.getElementById(retname)[dropdownIndex].value;
        if(dropdownValue >0)
        {
            //alert(dropdownValue);
            document.getElementById('inputname').value = dropdownValue;
        }
        else
        {
            document.getElementById('inputname').value = "00";
        }
        return;
        url2=page2; 
        var params2 = parrams2+'&';
        makerequest_sp(url2, params2, divid2);

     }
});         
}

Попробуйте добавить опцию:

dataType: "json"

Можете ли вы попробовать это без

contentType:application/x-www-form-urlencoded

Вы должны сделать некоторую работу на стороне сервера. Я вижу, что вы используете PHP на стороне сервера, но решение для веб-приложения.NET здесь: невозможно установить для типа контента значение 'application/json' в jQuery.ajax

Сделайте то же самое в PHP-скрипте, и он будет работать. Просто: при первом запросе браузер запрашивает у сервера, разрешено ли отправлять такие данные с таким типом, а второй запрос является правильным / разрешенным.

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

Перейдите по этой ссылке: используя Mode-Rewrite для проксирования, я добавляю эту строку в мой httpd.conf:

 RewriteRule ^solr/(.*)$ http://ip:8983/solr$1 [P]

Поэтому я могу просто публиковать данные в / solr вместо того, чтобы публиковать данные на http://ip:8983/solr/*. Тогда он будет публиковать данные в том же источнике.

Доводим до вашего сведения:

JSONP поддерживает только метод запроса GET.

* Отправить запрос по Firefox: *

$.ajax({
   type: 'POST',//<<===
   contentType: 'application/json',
   url: url,
   dataType: "json"//<<=============
    ...
});

Выше запрос, отправленный с помощью OPTIONS(while ==>введите: 'POST')!!!!

$.ajax({
    type: 'POST',//<<===
    contentType: 'application/json',
    url: url,
    dataType: "jsonp"//<<==============
    ...
});

Но вышеприведенный запрос отправлен GET(while ==>типа: 'POST')!!!!

Когда вы находитесь в "междоменной связи", будьте внимательны и осторожны.

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