66

我知道 AJAX 跨域策略。所以我不能只通过 ajax HTTP 请求调用“ http://www.google.com ”并将结果显示在我网站的某处。

我用 dataType "jsonp" 试了一下,这实际上可以工作,但我得到一个语法错误(显然是因为接收到的数据不是 JSON 格式的)

是否还有其他可能接收/显示来自外国域的数据?iFrame 遵循相同的政策?

4

11 回答 11

67

正如Andy E所指出的,使用 AJAX 获取跨域数据的唯一(简单)方法是使用服务器端语言作为代理。这是一个如何使用 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']);

就那么简单。请注意您可以或不能对抓取的数据做什么。

于 2010-04-01T08:29:32.737 回答
19

您需要将脚本标记动态插入到引用数据的页面中。使用 JSONP,您可以在脚本加载后执行一些回调函数。

JSONP上的维基百科页面有一个简洁的示例;脚本标签:

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

将返回包装在调用中的 JSON 数据parseResponse

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

(取决于getjsondomain1.com 上脚本的配置)

动态插入标签的代码类似于:

var s = document.createElement("script");
s.src = "http://domain1.com/getjson?jsonp=parseResponse";
s.type = "text/javascript";
document.appendChild(s);
于 2010-04-01T08:14:50.160 回答
16

您可以使用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 */}
);
于 2011-09-10T03:58:39.077 回答
11

不幸的是(或幸运的是)不是。跨域策略的存在是有原因的,如果它很容易绕过它,那么它作为一种安全措施就不会非常有效。除了 JSONP,唯一的选择是使用您自己的服务器代理页面

使用 iframe,它们受制于相同的策略。当然,您可以显示来自外部域的数据,只是不能对其进行操作。

于 2010-04-01T08:16:12.717 回答
4

我将此代码用于跨域 ajax 调用,我希望它对这里的帮助不止一个。我正在使用 Prototype 库,您可以对 JQuery 或 Dojo 或其他任何东西做同样的事情:

第一步:新建一个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 约束。

第2步:在任何你想异步拉取JSON的html页面中(我们称之为AJAJ~异步JAvascript + JSON :-)而不是使用XHTTPRequest对象的AJAX)做如下

//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 on rails 我刚刚做了

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

仅此而已,您现在可以从您的应用程序(小部件、地图等)中提取来自另一个域的数据,仅限 JSON 格式,不要忘记。

我希望它对您有所帮助,感谢您的耐心:-),请和平并为代码格式化感到抱歉,它无法正常工作

于 2010-08-30T13:21:03.590 回答
3

在做了一些研究之后,这个问题的唯一“解决方案”是调用:

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

这将询问用户是否允许网站继续运行。在他确认之后,无论数据类型如何,所有 ajax 调用都将被执行。

这适用于 mozilla 浏览器,在 IE < 8 中,用户必须以类似的方式允许跨域调用,某些版本需要在浏览器选项中进行配置。

chrome/safari:到目前为止,我还没有找到这些浏览器的配置标志。

使用 JSONP 作为数据类型会很好,但就我而言,我不知道我需要访问的域是否支持该格式的数据。

另一种方法是使用 HTML5 postMessage,它也可以跨域工作,但我不能让我的用户使用 HTML5 浏览器。

于 2010-04-06T09:31:59.553 回答
3

如果您使用 php 脚本从远程服务器获取答案,请在开头添加以下行:

header("Access-Control-Allow-Origin: *");
于 2016-05-23T07:09:20.843 回答
2

在我看来,JSONP 是最好的选择。尝试找出为什么会出现语法错误 - 你确定接收到的数据不是 JSON 吗?那么也许你以某种方式错误地使用了 API。

您可以使用的另一种方法,但我认为它不适用于您的情况,是在页面中有一个 iFrame,其中 src 位于您要调用的域中。让它为你做调用,然后使用 JS 在 iF​​rame 和页面之间进行通信。这将绕过跨域,但前提是您可以在要调用的域中拥有 iFrame 的 src。

于 2010-04-01T08:15:58.927 回答
1

这是一种简单的方法,无需使用任何花哨的东西,甚至是 JSON。

首先,创建一个服务器端脚本来处理您的请求。像http://www.example.com/path/handler.php

您将使用参数调用它,如下所示: .../handler.php?param1=12345¶m2=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);

这种方法的唯一限制是您可以发送到服务器的参数的最大长度。但是,您始终可以发送多个请求。

于 2014-06-08T04:45:22.110 回答
0

您可以使用 CORS 技术来配置两个服务器(运行 Javascript 的服务器和外部 API 服务器)

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

ps:答案https://stackoverflow.com/a/37384641/6505594也建议使用这种方法,并且它正在向其他所有人开放外部API服务器来调用它。

于 2017-05-31T19:23:26.927 回答
-4

我在 2 天内遇到了同样的问题,我找到了解决方案,并且在谷歌上搜索了很多之后它很优雅。我需要一些小部件客户端的 xss Ajax,这些客户端将数据流从层级网站拉到我的 Rails 应用程序。 我就是这样做的。

于 2010-08-27T14:36:58.423 回答