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 在 iFrame 和页面之间进行通信。这将绕过跨域,但前提是您可以在要调用的域中拥有 iFrame 的 src。
【讨论】:
@Nir:他得到了语法错误,因为他正在获取 HTML,而不是 JSON。这永远不会与 JSONP 一起工作 :-)【参考方案9】:这是一种简单的方法,无需使用任何花哨的东西,甚至是 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¶m2=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跨域调用的主要内容,如果未能解决你的问题,请参考以下文章