JQuery AJAX кросс-домен
Вот две страницы, test.php и testserver.php.
test.php
<script src="scripts/jq.js" type="text/javascript"></script>
<script>
$(function() {
$.ajax({url:"testserver.php",
success:function() {
alert("Success");
},
error:function() {
alert("Error");
},
dataType:"json",
type:"get"
}
)})
</script>
testserver.php
<?php
$arr = array("element1",
"element2",
array("element31","element32"));
$arr['name'] = "response";
echo json_encode($arr);
?>
Теперь моя проблема: когда оба эти файла находятся на одном сервере (локальный или веб-сервер), он работает и alert("Success")
называется; Если он находится на разных серверах, то есть testserver.php на веб-сервере и test.php на localhost, он не работает, и alert("Error")
выполняется. Даже если URL-адрес внутри ajax изменен на http://domain.com/path/to/file/testserver.php
15 ответов
Используйте JSONP.
JQuery:
$.ajax({
url:"testserver.php",
dataType: 'jsonp', // Notice! JSONP <-- P (lowercase)
success:function(json){
// do stuff with json (in this case an array)
alert("Success");
},
error:function(){
alert("Error");
}
});
PHP:
<?php
$arr = array("element1","element2",array("element31","element32"));
$arr['name'] = "response";
echo $_GET['callback']."(".json_encode($arr).");";
?>
Эхо может быть неправильным, я уже давно не использую php. В любом случае вам нужно вывести callbackName('jsonString')
обратите внимание на цитаты. jQuery передаст свое собственное имя обратного вызова, поэтому вам нужно получить его из параметров GET.
И как написал Стефан Кендалл, $.getJSON () - это сокращенный метод, но тогда вам нужно добавить 'callback=?'
к URL-адресу в качестве параметра GET (да, значение равно?, jQuery заменяет его собственным сгенерированным методом обратного вызова).
JSONP - хороший вариант, но есть более простой способ. Вы можете просто установить Access-Control-Allow-Origin
Заголовок на вашем сервере. Установка его в *
будет принимать междоменные запросы AJAX с любого домена. ( https://developer.mozilla.org/en/http_access_control)
Способ сделать это будет варьироваться от языка к языку, конечно. Вот это в Rails:
class HelloController < ApplicationController
def say_hello
headers['Access-Control-Allow-Origin'] = "*"
render text: "hello!"
end
end
В этом примере say_hello
action примет запросы AJAX от любого домена и вернет ответ "привет!".
Вот пример заголовков, которые он может вернуть:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
X-Ua-Compatible: IE=Edge
Etag: "c4ca4238a0b923820dcc509a6f75849b"
X-Runtime: 0.913606
Content-Length: 6
Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-07-09)
Date: Thu, 01 Mar 2012 20:44:28 GMT
Connection: Keep-Alive
Как бы легко это ни было, у него есть некоторые ограничения браузера. Смотрите http://caniuse.com/.
Вы можете контролировать это через HTTP-заголовок, добавив Access-Control-Allow-Origin. Установка * будет принимать междоменные AJAX-запросы от любого домена.
С помощью PHP это действительно просто, просто добавьте следующую строку в скрипт, к которому вы хотите иметь доступ извне вашего домена:
header("Access-Control-Allow-Origin: *");
Не забудьте включить модуль mod_headers в httpd.conf.
Вам нужно взглянуть на ту же политику происхождения:
В вычислениях одна и та же политика происхождения является важной концепцией безопасности для ряда языков программирования на стороне браузера, таких как JavaScript. Политика разрешает сценариям, работающим на страницах, исходящих с одного и того же сайта, получать доступ к методам и свойствам друг друга без особых ограничений, но запрещает доступ к большинству методов и свойств на страницах разных сайтов.
Чтобы вы могли получать данные, это должно быть:
Тот же протокол и хост
Вам нужно реализовать JSONP, чтобы обойти это.
Мне пришлось загрузить веб-страницу с локального диска "file:///C:/test/htmlpage.html", вызвать URL "http://localhost/getxml.php", и сделать это в браузерах IE8+ и Firefox12+, использовать jQuery v1.7.2 lib для минимизации стандартного кода. Прочитав десятки статей, наконец-то разобрался. Вот мое резюме.
- серверный скрипт (.php, .jsp, ...) должен возвращать HTTP-заголовок ответа Access-Control-Allow-Origin: *
- перед использованием jQuery ajax установите этот флаг в javascript: jQuery.support.cors = true;
- Вы можете установить флаг один или каждый раз перед использованием jQuery ajax-функции
- Теперь я могу читать XML-документ в IE и Firefox. Другие браузеры я не тестировал.
- Ответный документ может быть простым / текстовым, XML, JSON или любым другим
Вот пример вызова jQuery ajax с некоторыми sysouts отладки.
jQuery.support.cors = true;
$.ajax({
url: "http://localhost/getxml.php",
data: { "id":"doc1", "rows":"100" },
type: "GET",
timeout: 30000,
dataType: "text", // "xml", "json"
success: function(data) {
// show text reply as-is (debug)
alert(data);
// show xml field values (debug)
//alert( $(data).find("title").text() );
// loop JSON array (debug)
//var str="";
//$.each(data.items, function(i,item) {
// str += item.title + "\n";
//});
//alert(str);
},
error: function(jqXHR, textStatus, ex) {
alert(textStatus + "," + ex + "," + jqXHR.responseText);
}
});
Это правда, что политика одного и того же происхождения не позволяет JavaScript выполнять запросы между доменами, но спецификация CORS разрешает только тот тип доступа к API, который вы ищете, и поддерживается текущей партией основных браузеров.
Посмотрите, как включить общий доступ к ресурсам для клиента и сервера:
"Cross-Origin Resource Sharing (CORS) - это спецификация, которая обеспечивает действительно открытый доступ через границы домена. Если вы предоставляете общедоступный контент, рассмотрите возможность использования CORS, чтобы открыть его для универсального доступа JavaScript/ браузера".
Я использую сервер Apache, поэтому я использовал модуль mod_proxy. Включить модули:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
Затем добавьте:
ProxyPass /your-proxy-url/ http://service-url:serviceport/
Наконец, передайте proxy-url в ваш скрипт.
Это возможно, но вам нужно использовать JSONP, а не JSON. Ссылка Стефана указала вам в правильном направлении. Страница JQuery AJAX содержит больше информации о JSONP.
У Реми Шарпа есть подробный пример использования PHP.
Безопасность браузера предотвращает вызов ajax со страницы, размещенной в одном домене, на страницу, размещенную в другом домене; это называется " политика того же происхождения".
Есть несколько примеров использования JSONP, которые включают обработку ошибок.
Тем не менее, обратите внимание, что событие error не вызывается при использовании JSONP! См. Http://api.jquery.com/jQuery.ajax/ или jQuery ajax-запрос с использованием ошибки jsonp
Из документов Jquery ( ссылка):
Из-за ограничений безопасности браузера большинство запросов "Ajax" подчиняются той же политике происхождения; запрос не может успешно получить данные из другого домена, субдомена или протокола.
На запросы сценариев и JSONP не распространяются одинаковые ограничения политики происхождения.
Так что я бы взял, что вам нужно использовать jsonp для запроса. Но сам не пробовал.
Я знаю 3 способа решения вашей проблемы:
Во-первых, если у вас есть доступ к обоим доменам, вы можете разрешить доступ ко всем другим доменам, используя:
header("Access-Control-Allow-Origin: *");
или просто домен, добавив код ниже в файл.htaccess:
<FilesMatch "\.(ttf|otf|eot|woff)$"> <IfModule mod_headers.c> SetEnvIf Origin "http(s)?://(www\.)?(google.com|staging.google.com|development.google.com|otherdomain.net|dev02.otherdomain.net)$" AccessControlAllowOrigin=$0 Header add Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin </IfModule> </FilesMatch>
вы можете иметь ajax-запрос к php-файлу на вашем сервере и обрабатывать запрос к другому домену, используя этот php-файл.
- Вы можете использовать jsonp, потому что это не требует разрешения. для этого вы можете прочитать ответ нашего друга @BGerrissen.
Все работает, все что нужно:
PHP:
header('Access-Control-Allow-Origin: http://www.example.com');
header("Access-Control-Allow-Credentials: true");
header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');
JS (jQuery ajax):
var getWBody = $.ajax({ cache: false,
url: URL,
dataType : 'json',
type: 'GET',
xhrFields: { withCredentials: true }
});
Он должен работать в PHP, просто добавив это на обслуживаемую страницу:
header("Access-Control-Allow-Origin: *");
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
PS: я сделал свой собственный пакет xhr под названием sa_ajax с удобными и полезными методами. (https://github.com/osergioabreu/sa_ajax/)
Для Microsoft Azure это немного другое.
Azure имеет специальный параметр CORS, который необходимо установить. Это по сути то же самое за кулисами, но простая установка заголовка, о котором упоминает Джошуар, не сработает. Документацию Azure для включения междоменного домена можно найти здесь:
https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript
Я возился с этим в течение нескольких часов, прежде чем понял, что на моей хостинговой платформе есть эта особая настройка.