it-swarm.com.ru

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 
 Content-Length 46 
 Тайм-аут Keep-Alive = 15, макс. = 100 
 Connection Keep-Alive 
 Content-Type text/html 
 
 Заголовки запросов 
 Форма заказа хоста: 8888 
 User-Agent 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 
 Accept-Encoding 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-Method POST 
 Access-Control-Request-Headers x-запрашивается-с 

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

326
fitzgeraldsteele

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

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

Я использовал следующий код на стороне 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.

56
Juha Palomäki

Это статья центра разработчиков 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.

16
Mike C

Я исправил эту проблему, используя полностью основанное на 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 для последней части.

15
Mark McDonald

Это 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);
}
10
Chad Clark

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

7
Slav

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;
                }
    }
6
thinkhy

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

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

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

4
Slava0008

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

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

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

3
fboiton

Мне кажется, что если 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");

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

2
Elzo Valugi

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

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

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

2
Bijay Rungta

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

1
Niehztog

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

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

1
rynop

Решение этого:

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

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

1
Antonio Gulli

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

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

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

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

0
Drew

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

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

0
Fanda

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

dataType: "json",
ContentType: "application/json",
data: JSON.stringify({"method":"getStates", "program":"EXPLORE"}),  
0
Mary Jain

У меня уже есть этот код хорошо обрабатывает мою ситуацию 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 OR моим кодом, я не стал его искать, когда вы запрашиваете OPTIONS, он возвращает мой заголовок с правилами cors, но с результатом 302. Поэтому мой браузер не распознает как приемлемую ситуацию.

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

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

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

0
Ratata Tata

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

contentType:application/x-www-form-urlencoded

0
Mathias F

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

dataType: "json"

0
ScottE

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

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

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

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

0
Bernice
 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);

     }
});         
}
0
Naser Gulzade