@H_404_0@浏览器安全模型规定,XMLHttpRequest、框架(frame)等只能在一个域中通信。从安全角度考虑,这个规定很合理;但是,也确实给分布式(面向服务、混搭等等本周提到的概念)Web开发带来了麻烦。 @H_404_0@为了实现跨域通信,通常的解决方案有3种: @H_404_0@本地代理:
需要一些硬件设施(没有服务器的客户端无法运行),并且带宽和潜伏时间也要加倍(远程服务器-代理服务器-客户端)。 @H_404_0@Flash:
远程主机中需要部署一个crossdomain.xml文件,而且,Flash作为一门专有技术,其前途尚不明朗;换句话说,开发人员很可能要学习一种目标不确定的编程语言。 @H_404_0@Script标签:
无法确切知道内容是否有效,没有标准的实现方法,又可能被认为是一种“安全风险”。 @H_404_0@
在此,我建议使用一种新技术,也是一种独立于标准的方法,即通过script标签来跨域获取数据,名为JSON with Padding,或者就叫 JSONP。JSONP的原理很简单,但需要服务器端给予相应配合。大致来说,JSONP的实现思路就是在客户端编程时作好使用JSON数据的准备,然后再通过圆括号将这些数据括起来以创建一条有效的JavaScript语句(可能是一次有效的函数调用)。 @H_404_0@也就是说,客户端可以使用一个用于命名jsonp的查询参数来决定可以获取的数据。最简单的情况下,如果jsonp参数为空,则返回的数据就是被括在圆括号中的JSON。 @H_404_0@下面,我们就以del.icio.us的JSON API为例,来说明JSONP的原理。该API有一个“script tag”变量(即,可以将下面的URL作为script标签的src属性值,用以加载del.icio.us这个API提供的数据。——译者注)如下所示: @H_404_0@http://del.icio.us/feeds/json/bob/mochikit+interpreter:
if(typeof(DelicIoUs) == 'undefined') DelicIoUs = {}; DelicIoUs.posts = [{ "u": "http://mochikit.com/examples/interpreter/index.html","d": "Interpreter - JavaScript Interactive Interpreter","t": [ "mochikit","webdev","tool","tools","javascript","interactive","interpreter","repl" ] }]
如果用JSONP的方式来表示,那么与此具有相同语义的URL应该是这样的:
var delicIoUs_callbacks = {}; function getDelicIoUs(callback,url) { var uid = (new Date()).getTime(); delicIoUs_callbacks[uid] = function () { delete delicIoUs_callbacks[uid]; callback(); }; url += "?jsonp=" + encodeURIComponent("delicIoUs_callbacks[" + uid + "]"); // add the script tag to the document,cross fingers }; getDelicIoUs(doSomething,"http://del.icio.us/Feeds/json/bob/mochikit+interpreter");
根据以上假设,用于获取数据的URL应该如下所示:
delicIoUs_callbacks[12345]([{ "u": "http://mochikit.com/examples/interpreter/index.html","repl" ] }])