JavaScript跨域方法汇总


Posted in Javascript onOctober 16, 2014

做Web开发经常需要面对跨域问题,跨域问题的根源是浏览器安全中的同源策略,比如说,对于http://www.a.com/1.html来说:

1.http://www.a.com/2.html是同源的;
2.https://www.a.com/2.html是不同源的,原因是协议不同;
3.http://www.a.com:8080/2.html是不同源的,原因是端口不同;
4.http://sub.a.com/2.html是不同源的,原因是主机不同。

在浏览器中,<script>、<img>、<iframe>和<link>这几个标签是可以加载跨域(非同源)的资源的,并且加载的方式其实相当于一次普通的GET请求,唯一不同的是,为了安全起见,浏览器不允许这种方式下对加载到的资源的读写操作,而只能使用标签本身应当具备的能力(比如脚本执行、样式应用等等)。

最常见的跨域问题是Ajax跨域访问的问题,默认情况下,跨域的URL是无法通过Ajax访问的。这里我记录我所了解到的跨域的方法:

1. 服务器端代理,这没有什么可说的,缺点在于,默认情况下接收Ajax请求的服务端是无法获取到的客户端的IP和UA的。

2. iframe,使用iframe其实相当于开了一个新的网页,具体跨域的方法大致是,域A打开的母页面嵌套一个指向域B的iframe,然后提交数据,完成之后,B的服务端可以:

●返回一个302重定向响应,把结果重新指回A域;
●在此iframe内部再嵌套一个指向A域的iframe。

这两者都最终实现了跨域的调用,这个方法功能上要比下面介绍到的JSONP更强,因为跨域完毕之后DOM操作和互相之间的JavaScript调用都是没有问题的,但是也有一些限制,比如结果要以URL参数传递,这就意味着在结果数据量很大的时候需要分割传递,甚是麻烦;还有一个麻烦是iframe本身带来的,母页面和iframe本身的交互本身就有安全性限制。

3. 利用script标签跨域,这个办法也很常见,script标签是可以加载异域的JavaScript并执行的,通过预先设定好的callback函数来实现和母页面的交互。它有一个大名,叫做JSONP跨域,JSONP是JSON with Padding的略称。它是一个非官方的协议,明明是加载script,为啥和JSON扯上关系呢?原来就是这个callback函数,对它的使用有一个典型的方式,就是通过JSON来传参,即将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

在互联网上有很多JSONP的服务来提供数据,本质上就是跨域请求,并且在请求URL中指定好callback,比如callback=result,那么在获取到这些数据以后,就会自动调用result函数,并且把这些数据以JSON的形式传进去,例如(搜索“football”):

http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=football&callback=result

使用JQuery来调用就写成:

$.getJSON("http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=football&callback=?",function(data){

    //...

});

总的来说,JSONP的跨域方式的局限性在于,只能使用GET请求,并且不能解决不同域的两个页面之间如何进行JavaScript调用的问题。

4. Flash跨域:

它会访问目标网站根目录下面的crossdomain.xml文件,根据文件中的内容来确定是否允许此次跨域访问:

<cross-domain-policy>

    <allow-access-from domain="xxx.xxx.com" />

</cross-domain-policy>

5. img标签也可以使用,这也是一种非常常见的方法,功能上面弱一点,只能发送一个get请求,没有什么回调,Google的点击计数就是这样确定的。

6. window.PostMessage,这个算是HTML5新加入的为跨域通讯考虑的机制,只有Firefox 3、Safari 4和IE8及之后的版本支持。使用它向其它窗口发送消息的调用方式如下:

otherWindow.postMessage(message, targetOrigin);

在接收的窗口,需要设置一个事件处理函数来接收发过来的消息:
window.addEventListener("message", receiveMessage, false);

function receiveMessage(event){

    if (event.origin !== "http://example.org:8080")

        return;

}

注意这里必需要使用消息的origin和source属性来验证发送者的身份,否则会造成XSS漏洞。

7. Access Control

有一些浏览器支持Access-Control-Allow-Origin这样的响应头,比如:

header("Access-Control-Allow-Origin: http://www.a.com");

就指定了允许对www.a.com跨域访问。

8. window.name

这个东西其实以前被用作黑客XSS的手段,其本质是,当window的location变化的时候,页面会重新加载,但是有趣的是,这个window.name居然不发生变化,那么就可以用它来传值了。配合iframe,改变几次iframe的window对象,就完成了实用的跨域数据传递。

9. document.domain

这个方式适用于a.example.com和b.example.com这种跨域的通信,因为二者有一个共有的域,叫做example.com,只要设置document.domain为example.com就可以了,但是如果a.example1.com和b.example2.com之间要通信,它就没办法了。

10. Fragment Identitier Messaging(FIM)

这个方法很有意思,也需要iframe的配合。Fragment Identitier就是URL的井号(#)后面的经常用于锚点定位的部分,这部分的改变不会导致页面刷新,母窗口可以随便访问iframe的URL,而iframe也可以随便访问母窗口的URL,那这二者之间就可以通过改变Fragmement Identitier来实现通信了。缺点是Fragmement Identitier的改变会产生不必要的历史记录,而且也有长度限制;另外,有的浏览器不支持onhashchange事件。

11. Cross Frame(CF)

这种方法是上述FIM方法的变种,CF和FIM的本质其实在我的《GWT初体验》这篇文章里面都有介绍(只不过是被用来实现历史和后退功能了),它会动态创建一个不可见的iframe,指向异域,处理完以后,这个iframe的URL中的Fragment Identitier包含了处理结果,供母页面访问,而浏览器的URL没有任何变化。

12. Cookie+P3P协议

利用P3P协议下跨域访问Cookie的特性,来实现跨域访问,也算一奇招。P3P是W3C公布的一项隐私保护推荐标准,旨在为网上冲浪的Internet用户提供隐私保护。把Cookie的path设置为“/”,即没有任何域的限制,这个时候有的浏览器下面允许别的URL的页面来读取,有的则不允许,这种情况下需要在母页面响应的头上面设置P3P的头:

P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"
Javascript 相关文章推荐
统计jQuery中各字符串出现次数的工具
May 03 Javascript
javascript判断是手机还是电脑访问网页的简单实例分享
Jun 03 Javascript
javascript函数命名的三种方式及区别介绍
Mar 22 Javascript
jQuery获取table下某一行某一列的值实现代码
Apr 07 jQuery
bootstrap3 dialog 更强大、更灵活的模态框
Apr 20 Javascript
JavaScript使用ZeroClipboard操作剪切板
May 10 Javascript
前端MVVM框架解析之双向绑定
Jan 24 Javascript
浅谈Vue.js组件(二)
Apr 09 Javascript
解决Echarts2竖直datazoom滑动后显示数据不全的问题
Jul 20 Javascript
vue-cli3自动消除console.log()的调试信息方式
Oct 21 Javascript
JavaScript Dom实现轮播图原理和实例
Feb 19 Javascript
vue-router路由懒加载及实现的3种方式
Feb 28 Vue.js
js阻止事件追加的具体实现
Oct 15 #Javascript
用原生js做个简单的滑动效果的回到顶部
Oct 15 #Javascript
原生的html元素选择器类似jquery选择器
Oct 15 #Javascript
用原生JS获取CLASS对象(很简单实用)
Oct 15 #Javascript
通过JS动态创建一个html DOM元素并显示
Oct 15 #Javascript
javascript模拟实现ajax加载框实例
Oct 15 #Javascript
jquery幻灯片插件bxslider样式改进实例
Oct 15 #Javascript
You might like
让你的PHP同时支持GIF、png、JPEG
2006/10/09 PHP
队列在编程中的实际应用(php)
2010/09/04 PHP
php引用计数器进行垃圾收集机制介绍
2012/09/19 PHP
laravel多条件查询方法(and,or嵌套查询)
2019/10/09 PHP
ExtJS 2.0实用简明教程 之Border区域布局
2009/04/29 Javascript
js实现仿阿里巴巴城市选择框效果实例
2015/06/24 Javascript
javascript获取重复次数最多的字符
2015/07/08 Javascript
Zero Clipboard实现浏览器复制到剪贴板的方法(多个复制按钮)
2016/03/24 Javascript
javascript数字验证的实例代码(推荐)
2016/08/20 Javascript
jQuery给指定的table动态添加删除行的操作方法
2016/10/12 Javascript
利用HTML5+Socket.io实现摇一摇控制PC端歌曲切换
2017/01/13 Javascript
JS实现简单的选择题测评系统代码思路详解(demo)
2017/09/03 Javascript
基于jQuery使用Ajax动态执行模糊查询功能
2018/07/05 jQuery
在JavaScript中如何访问暂未存在的嵌套对象
2019/06/18 Javascript
vue之a-table中实现清空选中的数据
2019/11/07 Javascript
vue开发中遇到的问题总结
2020/04/07 Javascript
JS 设计模式之:工厂模式定义与实现方法浅析
2020/05/06 Javascript
vue-cli3项目打包后自动化部署到服务器的方法
2020/09/16 Javascript
vue element-ul实现展开和收起功能的实例代码
2020/11/25 Vue.js
[00:09]DOTA2新版本PA至宝特效动作展示
2014/11/19 DOTA
[01:06:42]VP vs NewBee Supermajor 胜者组 BO3 第二场 6.5
2018/06/06 DOTA
[59:42]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python实现的几个常用排序算法实例
2014/06/16 Python
快速了解Python开发中的cookie及简单代码示例
2018/01/17 Python
python 处理dataframe中的时间字段方法
2018/04/10 Python
python中itertools模块zip_longest函数详解
2018/06/12 Python
打造经典复古风格的品牌:Alice + Olivia(爱丽丝+奥利维亚)
2016/09/07 全球购物
加拿大最大的书店:Indigo
2017/01/01 全球购物
欧洲最大的化妆品连锁公司:Douglas道格拉斯
2017/05/06 全球购物
Stefania Mode英国:奢华设计师和时尚服装
2017/10/23 全球购物
导师推荐信范文
2014/05/09 职场文书
老干部工作先进集体事迹材料
2014/05/21 职场文书
采购员岗位职责范本
2015/04/07 职场文书
Python的这些库,你知道多少?
2021/06/09 Python
Python实现位图分割的效果
2021/11/20 Python
电脑只能进入安全模式无法正常启动的解决办法
2022/04/08 数码科技