日期:2014-05-16 浏览次数:20895 次
??? 这几天被跨域问题困扰了很久,现在整理下思绪,以备不时之需。
??
???? 由于安全方面的考虑,JS被限制了跨域访问的能力,但是有时候我们希望能够做一些合理的跨域访问的事情,那么怎么办呢?
这里分两类情况:
一、基于同一父域的子域之间页面的访问;参见如下3个domain域:sina.com、news.sina.com、mail.sina.com;它们有相同的父域taobao.com。
二、基于不同父域页面之间的访问;参见如下3个domain域:taobao.com、baidu.com、sina.com.cn;它们具有不同的父域。
根据不同的跨域需求,跨域技术可以归为下面几类:
?
方案1:服务器Proxy
域A 的页面JS需要访问域B下的链接获取数据,该方案在域A的服务器端建立一个Proxy程序(可能是PHP\ASP、servlet等任何服务端程序),域A的页面 JS直接调用本域下的Proxy程序,proxy程序负责将请求发送给域B下的链接并获取到数据,最后再通过Proxy将数据返回给页面JS使用。
经过的访问流程就是: 域A下JS --> 域A 下Proxy -- > 域B下的链接
Proxy方案优点是可以适用用于几乎所有的跨域访问,而且只需要要一个域中进行开发,另一个域可以提供任何类型格式的数据。缺点是这种方案经过了中间Proxy,所以延迟可能稍微大一点,并且会加重本域服务器的负荷,开发工作量也稍微大一点。
方案2:隐藏iframe、共享domain :
通常情况下,我们会用与下面类似的代码来创建一个XMLHttpRequest对象:
factories = [
function() { return new XMLHttpRequest(); },
function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
];
function newRequest() {
for(var i = 0; i < factories.length; i++) {
try{
var factory = factories[i];
return factory();
} catch(e) {}
}
return null;
}
?
上面的代码中引用ActiveXObject,是为了兼容IE6系列浏览器。每次我们调用newRequest函数,就获得了一个刚刚创建的 Ajax对象,然后用这个Ajax对象来发送HTTP请求。例如,下面的代码向abc.example.com发送了一个GET请求:
var request = newRequest();
request.open("GET", "http://abc.example.com" );
request.send(null);
?
假设上面的代码包含在一个abc.example.com域名下的页面里,则这个GET请求可以正常发送成功,没有任何问题。然而,如果现在要向def.example.com发送请求,则出现跨域问题,JavaScript引擎抛出异常。
解决的办法是,在def.example.com域下放置一个跨域文件,假设叫crossdomain.html;然后将前面的 newRequest函数的定义移到这个跨域文件中;最后像之前修改document.domain值的做法一样,在crossdomain.html文件和 abc.example.com域下调用Ajax的页面顶端,都加上:
?
<script type="text/javascript">
document.domain = "example.com";
</script>
?
?
为了使用跨域文件,我们在abc.example.com域下调用Ajax的页面中嵌入一个隐藏的指向跨域文件的iframe,例如:
<iframe name="xd_iframe" style="display:none" src="http://def.example.com/crossdomain.html"></iframe>
这时abc.example.com域下的页面和跨域文件crossdomain.html都在同一个域(example.com)下,我们可以在abc.example.com域下的页面中去调用crossdomain.html中的newRequest函数:
var request = window.frames["xd_iframe"].newRequest();
这样获得的request对象,就可以向http://def.example.com发送HTTP请求了。
隐藏iframe方式也很简单,它可以处理任何返回的数据格式,但它只适用在具有同一个父域下的跨域请求上,并且要求其他域得配合开发,即需要设置document.domain。
方案3: JSONP 跨域GET请求 ( 通过Script标签) :
在域A页面http://