2009-07-08 2 views
308

Возникли проблемы с тем, что я думал, был относительно простой 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 на сервере всегда «ОПЦИИ», а данные $ _POST не отображаются. Apache регистрирует запрос как тип «OPTIONS»:

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

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

 
Response Headers 
Date: Wed, 08 Jul 2009 21:22:17 GMT 
Server:Apache/2.0.59 (Unix) PHP/5.2.6 DAV/2 
X-Powered-By: PHP/5.2.6 
Content-Length 46 
Keep-Alive timeout=15, max=100 
Connection Keep-Alive 
Content-Type text/html 

Request Headers 
Host orderform: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 
Accept text/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 
Connection keep-alive 
Origin http://ux.inetu.act.org 
Access-Control-Request-Method POST 
Access-Control-Request-Headers x-requested-with 

Вот картина выхода Firebug:

+0

Можете ли вы опубликовать ответ об ответчике и запросить ответчик. Я не получаю никаких ошибок при запуске аналогичного кода в Firefox. – MitMaro

+0

Добавлена ​​информация заголовка и изображение из Firebug. – fitzgeraldsteele

+0

Только эта проблема возникла при внедрении встроенного веб-сервера. Спасибо за просьбу :) –

ответ

161

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

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

Примечание. Обратитесь к http://docs.jquery.com/Release:jQuery_1.2/Ajax#Cross-Domain_getJSON_.28using_JSONP.29 за информацией об использовании JSONP. Вам понадобится дополнительный «=?» в строке запроса, чтобы вызвать JSONP – phirschybar

+23

, почему firefox - единственный браузер для этого? Я хочу, чтобы сообщение не получилось. – Maslow

+0

$ .getScript должен быть возможен междоменным, см. Http://docs.jquery.com/Release:jQuery_1.2/Ajax#Cross-Domain_getScript (но это не для меня в FF 3.6) – blueyed

2

Я, кажется, что если существует 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"); 

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

+0

Получил то же самое с этим ... подумал, что мне следует использовать $ .ajax(), чтобы я мог хотя бы получить отладочную информацию об ошибке. – fitzgeraldsteele

0

Вы можете попробовать это без

contentType:application/x-www-form-urlencoded

+0

Тот же результат, я боюсь. – fitzgeraldsteele

0

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

DATATYPE: ""

JSON
+2

, что сработало, почему json считается «безопасным» для междоменных запросов? –

+1

не работает для запросов jQuery для WCF – PositiveGuy

4

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

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

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

16

Этот mozilla developer center article описывает различные сценарии запроса междоменные. В статье, как представляется, указывается, что запрос 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.

0

У меня была аналогичная проблема с приложением API Facebook.

Единственный CONTENTTYPE, который не послал Preflighted запрос, казалось, только текст/обычный ... не все остальные параметры, упомянутые в Mozilla here

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

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

+0

Спасибо. text/plain решил мою проблему. – jahackbeth

1

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

54

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

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

+0

Ваше изменение о фактическом ответе POST/GET немного страшно; если кто-нибудь сможет это подтвердить, пожалуйста, сообщите нам об этом! – Arjan

+0

Я не знаю, является ли это ошибкой или функцией, но похоже, что кто-то еще ее заметил. См. Например, http://kodemaniak.de/?p=62 и поиск «пустого тела ответа» –

+2

Существует разница между простыми запросами и запросами на предполетную проверку. Ваше «решение» будет работать только с запросами preflight, поэтому это не реальное решение. Всякий раз, когда вы получаете заголовок «Origin:» в заголовках запроса, вы должны ответить тем, что это разрешено. –

2

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

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

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

10

Этот 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); 
} 
+0

Это может быть вопросом вкуса, но * всегда * отправка этих заголовков ответов (также для 'GET',' POST', ...) мне слишком по душе. (И, интересно, всегда ли они посылают эти спецификации со спецификациями?) – Arjan

+3

оберните его if ($ _ SERVER ['HTTP_ORIGIN']). Если этот заголовок есть, это запрос CORS, если нет, то нет необходимости отправлять что-либо. –

1

Решение это:

  1. использование DATATYPE: json
  2. добавить &callback=? в свой адрес

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

+1

Почему бы вам не показать код – PositiveGuy

15

Я исправил эту проблему, используя полностью основанное на Apache решение.В моем ВХосте/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 выполняет свой целевой сценарий. Кредит отправляется на friendly ServerFault folk для последней части.

+0

Ваш ответ помог мне, но если вам нужна какая-то логика для CORS, он не решает полностью. –

7

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

+12

Несовместим с методом POST. –

+1

Он работает с методом GET, но это очень ограниченное решение. Например, при этом вы не можете отправить ответ с определенным заголовком, включая токен. – svassr

3

У нас была проблема, как это с ASP.Net. Наш IIS возвращал ошибку внутреннего сервера при попытке выполнить jQuery $.post, чтобы получить некоторый html-контент из-за того, что PageHandlerFactory был ограничен, чтобы отвечать только GET,HEAD,POST,DEBUG Глаголы. Таким образом, вы можете изменить это ограничение, добавив глагол «ВАРИАНТЫ» в список или выбрав «Все глаголы» Вы можете изменить это в своем диспетчере IIS, выбрав свой веб-сайт, затем выбрав «Сопоставление обработчиков», дважды щелкнув в своем PageHandlerFactory для * .apx, как вам нужно (мы используем интегрированный пул приложений с фреймворком 4.0). Нажмите «Ограничения запроса», затем перейдите в Таблицу «Глаголы» и примените свое изменение.

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

1

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

How do I send a cross-domain POST request via JavaScript?

0
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

Вопрос был отобран еще 6 месяцев назад. Как это решить? – Barmar

0

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

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

0

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

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

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

Следуйте этому URL: Using Mode-Rewrite for proxying, добавить эту строку в моей httpd.conf:

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

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

-1

Пожалуйста, обратите внимание:

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

* Отправить запрос на светлячок: *

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

Над просьбой послать ВАРИАНТОВ (в то время как ==>типа: 'POST') !!!!

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

Но выше просьбой отправить по GET (в то время как ==>типа: 'POST') !!!!

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

3

виновного предполетной запрос, используя параметры метода

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

Web спецификация см: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

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

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; 
       } 
    } 
+1

Этот ответ очень полезен. Тот факт, что браузер отправляет запрос предварительной проверки с помощью метода OPTIONS, неочевиден. – Normangorman

0

У меня уже есть этот код обработки хорошо мою Корс ситуацию в 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 результата.

Смежные вопросы