AJAX跨域调用

Posted

技术标签:

【中文标题】AJAX跨域调用【英文标题】:AJAX cross domain call 【发布时间】:2011-02-03 06:39:51 【问题描述】:

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

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

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

【问题讨论】:

【参考方案1】:

使用 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']);

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

【讨论】:

并且要非常清楚,这样的代理是一个严重的安全漏洞......至少列出可接受的地址,不要盲目地接受任何传递的地址。在这里查看一个不错的代理脚本:benalman.com/projects/php-simple-proxy 但是当目标页面有非绝对URL和相对链接时,它不会破坏布局吗? @ChristianStuder 为什么会有问题?【参考方案2】:

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

JSONP 上的***页面有一个简洁的例子;脚本标签:

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

将返回封装在对 parseResponse 的调用中的 JSON 数据:

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

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

动态插入标签的代码如下:

var s = document.createElement("script");
s.src = "http://domain1.com/getjson?jsonp=parseResponse";
s.type = "text/javascript";
document.appendChild(s);

【讨论】:

仅当您收到 JSON 数据或纯文本或 HTML 数据时,这是否有效? @jAndy:这仅适用于 JSONP(包括回调函数)数据。 仅适用于 GET 请求。没有 PUT、DELETE 或 POST。所以没有 RESTful 接口。【参考方案3】:

您可以使用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 */
);

【讨论】:

【参考方案4】:

不幸(或幸运)没有。跨域策略的存在是有原因的,如果它很容易绕过它,那么它作为一种安全措施就不会非常有效。除了 JSONP,唯一的选择是proxy the pages using your own server。

对于 iframe,它们需要遵守相同的政策。当然,您可以显示来自外部域的数据,只是不能对其进行操作。

【讨论】:

你说的“你就是不能操纵它”是什么意思?例如,您不能将某些数据加载到 iFrame 中并通过 jQuery 选择器读取该数据? @jAndy:不,当访问不同域的文档时,对 99% 的 DOM 的访问被阻止。跨文档消息传递是可能的(使用 HTML5/现代浏览器),但必须由双方实现。【参考方案5】:

我将此代码用于跨域 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 约束。

Step2:在任何你想异步拉取 JSON 的 html 页面中(我们称之为 AJAJ ~ Asynchronous 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 格式,不要忘记。

希望对您有所帮助,感谢您的耐心等待 :-),对代码格式化表示抱歉,它不能正常工作

【讨论】:

【参考方案6】:

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

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

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

这适用于 mozilla 浏览器,在 IE

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

使用 JSONP 作为数据类型会很好,但在我的情况下,我不知道我是否需要一个域 访问支持该格式的数据。

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

【讨论】:

您并没有让您的用户使用 HTML5 浏览器,而是让他们成为一种服务 :-)【参考方案7】:

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

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

【讨论】:

【参考方案8】:

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

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

【讨论】:

@Nir:他得到了语法错误,因为他正在获取 HTML,而不是 JSON。这永远不会与 JSONP 一起工作 :-)【参考方案9】:

这是一种简单的方法,无需使用任何花哨的东西,甚至是 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);

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

【讨论】:

【参考方案10】:

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

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

p.s.:https://***.com/a/37384641/6505594 的答案也是在建议这种方法,它正在向其他人开放外部 API 服务器来调用它。

【讨论】:

【参考方案11】:

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

【讨论】:

以上是关于AJAX跨域调用的主要内容,如果未能解决你的问题,请参考以下文章

如何解决IE8下Ajax调用时跨域的问题

跨域 AJAX 调用 [重复]

AJAX跨域调用

为啥不允许跨域 AJAX 调用?

Ajax 跨域调用

跨域 Ajax 调用与 php 请求 [重复]