JQuery AJAX кросс-домен

477

Вот две страницы, 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

Фироза Хуссейн
источник
38
Для людей, заходящих. Прочтите это, чтобы понять, как работают междоменные вызовы javascript stackoverflow.com/a/11736771/228656
Абдул Муним
1
Я написал ответ на этот вопрос здесь: Загрузка междоменной html-страницы с помощью jQuery AJAX - последней, поддерживающей https
jherax

Ответы:

412

Используйте 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 заменяет его собственным сгенерированным методом обратного вызова).

BGerrissen
источник
2
Почему вам нужно вернуться callbackName('/* json */')вместо callbackName(/* json */)?
Эрик
3
@eric обратный вызов ожидает строку JSON. Теоретически, объект может также работать, но не уверен, как jQuery реагирует на это, он может выдать ошибку или потерпеть неудачу.
BGerrissen
Я получаю следующую ошибку. Ошибка синтаксиса: отсутствует; перед оператором {"ResultCode": 2}. Где {"ResultCode": 2} является ответом. Пожалуйста посоветуй.
user2003356
@ user2003356 похоже, что вы возвращаете простой JSON вместо JSONP. Вам необходимо вернуть что-то вроде: callbackFunction ({"ResultCode": 2}). jQuery добавляет параметр GET 'callback' к запросу, это имя функции обратного вызова, которую использует jquery, и должно быть добавлено в ответ.
Б.Герриссен
2
Сейчас 2016 год. CORS теперь широко поддерживаемый стандарт, в отличие от JSONP, который можно назвать только хаком. Ответ @ joshuarh ниже должен быть предпочтительным сейчас.
Вики Чиджвани
202

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действие будет принимать запросы 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/#feat=cors .

joshuarh
источник
12
Jsonp не поддерживал пост, ставил и удалял. Ваше решение прекрасно работает.
TonyTakeshi
35
в заголовке PHP («Access-Control-Allow-Origin: *»);
SparK
9
@Warrior Если вы используете .post()метод jQuery, вы должны включить междоменную поддержку в jQuery. Это делается с этим: $.support.cors = true.
Фридерике
21
Каковы последствия безопасности для настройки сервера таким образом?
Джон Шнайдер
19
Было бы лучше разрешить использовать только те домены, с которыми вы хотите обмениваться данными, вместо использования карточки "*".
Себастьян Гриньоли
32

Вы можете контролировать это через HTTP-заголовок, добавив Access-Control-Allow-Origin . Установка * будет принимать междоменные AJAX-запросы от любого домена.

С помощью PHP это действительно просто, просто добавьте следующую строку в скрипт, к которому вы хотите иметь доступ извне вашего домена:

header("Access-Control-Allow-Origin: *");

Не забудьте включить модуль mod_headers в httpd.conf.

Адоржан Принц
источник
ты спас мой день
NomanJaved
20

Вам нужно взглянуть на ту же политику происхождения :

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

Чтобы вы могли получить данные, это должно быть:

Тот же протокол и хост

Вам нужно реализовать JSONP, чтобы обойти это.

Sarfraz
источник
17

Мне пришлось загрузить веб-страницу с локального диска «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);
    }
});
Whome
источник
1
Я написал ответ на этот вопрос здесь: Загрузка междоменной html-страницы с помощью jQuery AJAX - последней, поддерживающей https
jherax
Для самого лучшего момента: в PHP добавьте эту строку в скрипт:header("Access-Control-Allow-Origin: *");
T30
1
@ Кто, ОЧЕНЬ большое спасибо за ваш ответ. Вы мне очень помогли. Приветствия.
Луис Миланезе
10

Это правда, что политика одного и того же происхождения не позволяет JavaScript выполнять запросы между доменами, но спецификация CORS разрешает только тот тип доступа к API, который вы ищете, и поддерживается текущей партией основных браузеров.

Посмотрите, как включить общий доступ к ресурсам для клиента и сервера:

http://enable-cors.org/

«Cross-Origin Resource Sharing (CORS) - это спецификация, которая обеспечивает действительно открытый доступ через границы домена. Если вы предоставляете общедоступный контент, рассмотрите возможность использования CORS, чтобы открыть его для универсального доступа JavaScript / браузера».

Джейсон
источник
9

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

zenio
источник
8

Безопасность браузера предотвращает вызов ajax со страницы, размещенной в одном домене, на страницу, размещенную в другом домене; это называется « политика того же происхождения ».

Джейкоб Маттисон
источник
4

Из документов Jquery ( ссылка ):

  • Из-за ограничений безопасности браузера большинство запросов «Ajax» подчиняются той же политике происхождения; запрос не может успешно получить данные из другого домена, субдомена или протокола.

  • На запросы сценариев и JSONP не распространяются одинаковые ограничения политики происхождения.

Поэтому я бы взял, что вам нужно использовать jsonp для запроса. Но сам не пробовал.

Уильям Клеменс
источник
2

Я знаю 3 способа решения вашей проблемы:

  1. Во-первых, если у вас есть доступ к обоим доменам, вы можете разрешить доступ ко всем другим доменам, используя:

    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>

  2. вы можете иметь ajax-запрос к php-файлу на вашем сервере и обрабатывать запрос к другому домену, используя этот php-файл.

  3. Вы можете использовать jsonp, потому что это не требует разрешения. для этого вы можете прочитать ответ нашего друга @BGerrissen.
Ali_Hr
источник
0

Для Microsoft Azure это немного другое.

Azure имеет специальный параметр CORS, который необходимо установить. Это по сути то же самое за кулисами, но простая установка заголовка, о котором упоминает Джошуар, не сработает. Документацию по Azure для включения междоменного домена можно найти здесь:

https://docs.microsoft.com/en-us/azure/app-service-api/app-service-api-cors-consume-javascript

Я возился с этим несколько часов, прежде чем понял, что на моей хостинговой платформе есть эта особая настройка.

Джош Шульц
источник
0

все работает, все что нужно:

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 }
});
Паун Нарцис Юлиан
источник