AJAX междоменный вызов - PullRequest
       30

AJAX междоменный вызов

65 голосов
/ 01 апреля 2010

Я знаю о междоменной политике AJAX. Поэтому я не могу просто позвонить "http://www.google.com" через HTTP-запрос ajax и отобразить результаты где-то на моем сайте.

Я пробовал это с dataType "jsonp", который на самом деле работал бы, но я получаю синтаксическую ошибку (очевидно, потому что полученные данные не отформатированы в JSON)

Есть ли другая возможность получать / отображать данные из чужого домена? iFrames следуют той же политике?

Ответы [ 11 ]

65 голосов
/ 01 апреля 2010

Единственный (простой) способ получения междоменных данных с использованием AJAX - использовать язык на стороне сервера в качестве прокси, как отмечал Andy E Вот небольшой пример того, как реализовать это с помощью jQuery:

JQuery часть:

$.ajax({
    url: 'proxy.php',
    type: 'POST',
    data: {
        address: 'http://www.google.com'
    },
    success: function(response) {
        // response now contains full HTML of google.com
    }
});

И PHP (proxy.php):

echo file_get_contents($_POST['address']);

Все просто. Просто знайте, что вы можете или не можете делать со скребковыми данными.

19 голосов
/ 01 апреля 2010

Вам нужно будет динамически вставить тег скрипта на страницу, которая ссылается на данные. Используя JSONP, вы можете выполнить некоторую функцию обратного вызова после загрузки скрипта.

Страница википедии на JSONP содержит краткий пример; тег сценария:

<script type="text/javascript" src="http://domain1.com/getjson?jsonp=parseResponse">
</script>

вернет данные JSON, заключенные в вызов, в parseResponse:

parseResponse({"Name": "Cheeso", "Rank": 7})

(в зависимости от конфигурации скрипта getjson на domain1.com)

Код для динамической вставки тега будет выглядеть примерно так:

var s = document.createElement("script");
s.src = "http://domain1.com/getjson?jsonp=parseResponse";
s.type = "text/javascript";
document.appendChild(s);
16 голосов
/ 10 сентября 2011

Вы можете использовать YQL для выполнения запроса без необходимости размещения собственного прокси. Я сделал простую функцию, чтобы упростить запуск команд:

function RunYQL(command, callback){
     callback_name = "__YQL_callback_"+(new Date()).getTime();
     window[callback_name] = callback;
     a = document.createElement('script');
     a.src = "http://query.yahooapis.com/v1/public/yql?q="
             +escape(command)+"&format=json&callback="+callback_name;
     a.type = "text/javascript";
     document.getElementsByTagName("head")[0].appendChild(a);
}

Если у вас есть jQuery, вы можете использовать вместо него $ .getJSON.

Образец может быть таким:

RunYQL('select * from html where url="http://www.google.com/"',
       function(data){/* actions */}
);
11 голосов
/ 01 апреля 2010

К сожалению (или к счастью) нет. Междоменная политика существует по определенной причине, если бы ее было легко обойти, тогда она не была бы очень эффективной в качестве меры безопасности. Кроме JSONP, единственный вариант - прокси страниц, используя ваш собственный сервер .

С помощью iframe они подчиняются одной и той же политике. Конечно, вы можете отображать данные из внешнего домена, вы просто не можете ими манипулировать.

4 голосов
/ 30 августа 2010

Я использую этот код для междоменного вызова ajax, я надеюсь, что он поможет больше, чем один здесь. Я использую библиотеку Prototype, и вы можете сделать то же самое с JQuery, Dojo или чем-то еще:

Шаг 1: создайте новый файл js и поместите этот класс внутрь, я назвал его xss_ajax.js

var WSAjax = Class.create ({
    initialize: function (_url, _callback){
        this.url = _url ;
        this.callback = _callback ;
        this.connect () ;
    },
    connect: function (){
        var script_id = null;
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', this.url);
        script.setAttribute('id', 'xss_ajax_script');

        script_id = document.getElementById('xss_ajax_script');
        if(script_id){
            document.getElementsByTagName('head')[0].removeChild(script_id);
        }

        // Insert <script> into DOM
        document.getElementsByTagName('head')[0].appendChild(script);
    },
    process: function (data){
        this.callback(data) ;
    }

}) ;

Этот класс создает динамический элемент сценария, атрибуты src которого предназначены для вашего поставщика данных JSON (фактически, JSON-P, поскольку ваш удаленный сервер должен предоставлять данные в этом формате :: call_back_function (// json_data_here) ::, поэтому, когда тег сценария Если ваш JSON создан, то он будет напрямую обработан как функция (на шаге 2 мы поговорим о передаче имени метода обратного вызова на сервер), основная идея этого заключается в том, что сценарий, такой как элементы img, не связан с ограничениями SOP.

Step2: на любой html-странице, где вы хотите получить JSON асинхронно (мы называем это AJAJ ~ Asynchronous JAvascript + JSON :-) вместо AJAX, в котором используется объект XHTTPRequest), выполните следующие действия

//load Prototype first
//load the file you've created in step1


var xss_crawler = new WSAjax (
     "http://your_json_data_provider_url?callback=xss_crawler.process"
 ,   function (_data){
            // your json data is _data and do whatever you like with it 
        }) ;

Вы помните обратный вызов на шаге 1? поэтому мы передаем его на сервер, и он возвращает JSON, внедренный в этот метод, поэтому в нашем случае сервер вернет корректный код javascript xss_crawler.process (// the_json_data), помните, что xss_crawler является экземпляром класса WSAjax. Код сервера зависит от вас (если он ваш), но большинство провайдеров данных Ajax позволяют указывать метод обратного вызова в параметрах, как мы. В Ruby на рельсах я просто сделал

render :json=>MyModel.all(:limit=>10), :callback => params[:callback],:content_type => "application/json"

и все, теперь вы можете извлекать данные из другого домена из ваших приложений (виджетов, карт и т. Д.), Только в формате JSON, не забывайте.

Я надеюсь, что это было полезно, спасибо за ваше терпение :-), мир и простите за форматирование кода, это не работает хорошо

4 голосов
/ 06 апреля 2010

после некоторых исследований единственное «решение» этой проблемы - позвонить:

if($.browser.mozilla)
   netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');

при этом пользователю будет предложено продолжить работу сайта. После того как он подтвердил это, все Ajax-вызовы будут выполняться независимо от типа данных.

Это работает для браузеров Mozilla, в IE <8, пользователь должен разрешить междоменный вызов аналогично, некоторые версии необходимо настроить в настройках браузера. </p>

chrome / safari: флаг настройки для этих браузеров пока не найден.

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

Еще один способ - использовать HTML5 postMessage, который работает и в междоменных областях, но я не могу позволить себе обречь моих пользователей на браузеры HTML5.

3 голосов
/ 23 мая 2016

Если вы используете скрипт php для получения ответа от удаленного сервера, добавьте эту строку в начале:

header("Access-Control-Allow-Origin: *");
2 голосов
/ 01 апреля 2010

JSONP - лучший вариант, на мой взгляд. Попытайтесь выяснить, почему вы получаете синтаксическую ошибку - вы уверены, что полученные данные не являются JSON? Тогда, может быть, вы как-то неправильно используете API.

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

1 голос
/ 08 июня 2014

Вот простой способ сделать это, не прибегая к чему-либо необычному или даже JSON.

Сначала создайте серверный скрипт для обработки ваших запросов. Что-то вроде http://www.example.com/path/handler.php

Вы будете вызывать его с параметрами, например: ... / handler.php? Param1 = 12345 & param2 = 67890

Внутри него, после обработки полученных данных, вывод :

document.serverResponse('..all the data, in any format that suits you..');
// Any code could be used instead, because you dont have to encode this data
// All your output will simply be executed as normal javascript

Теперь в клиентском скрипте используйте следующее:

document.serverResponse = function(param){ console.log(param) }

var script = document.createElement('script');
script.src='http://www.example.com/path/handler.php?param1=12345&param2=67890';
document.head.appendChild(script);

Единственным ограничением этого подхода является максимальная длина параметров, которые вы можете отправить на сервер. Но вы всегда можете отправить несколько запросов.

0 голосов
/ 31 мая 2017

Вы можете использовать технологию CORS для настройки обоих серверов (сервера, на котором работает Javascript, и внешнего сервера API)

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

p.s .: ответ https://stackoverflow.com/a/37384641/6505594 также предлагает этот подход, и он открывает внешний сервер API для всех остальных, чтобы он вызывал его.

...