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 相关文章推荐
用js脚本控制asp.net下treeview的NodeCheck的实现代码
Mar 02 Javascript
用JS控制回车事件的代码
Feb 20 Javascript
Javascript将字符串日期格式化为yyyy-mm-dd的方法
Oct 27 Javascript
jQuery grep()方法详解及实例代码
Oct 30 Javascript
jQuery和JavaScript节点插入元素的方法对比
Nov 18 Javascript
JavaScript与JQUERY获取元素的宽、高和位置
Feb 26 Javascript
JS中SetTimeout和SetInterval使用初探
Mar 23 Javascript
[js高手之路]设计模式系列课程-发布者,订阅者重构购物车的实例
Aug 29 Javascript
Angular4表单验证代码详解
Sep 03 Javascript
微信小程序实践之动态控制组件的显示/隐藏功能
Jul 18 Javascript
Element-ui el-tree新增和删除节点后如何刷新tree的实例
Aug 31 Javascript
Vue实现返回顶部按钮实例代码
Oct 21 Javascript
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
phpadmin如何导入导出大数据文件及php.ini参数修改
2013/02/18 PHP
[原创]php常用字符串输出方法分析(echo,print,printf及sprintf)
2016/07/09 PHP
借用Google的Javascript API Loader来加速你的网站
2009/01/28 Javascript
Prototype Class对象学习
2009/07/19 Javascript
TextArea不支持maxlength的解决办法(jquery)
2011/09/13 Javascript
JS实现图片预加载无需等待
2012/12/21 Javascript
JS实现自适应高度表单文本框的方法
2015/02/25 Javascript
JS实现往下不断流动网页背景的方法
2015/02/27 Javascript
原生js实现的贪吃蛇网页版游戏完整实例
2015/05/18 Javascript
js实现字符串转日期格式的方法
2015/05/20 Javascript
jquery实现隐藏在左侧的弹性弹出菜单效果
2015/09/18 Javascript
以JavaScript来实现WordPress中的二级导航菜单的方法
2015/12/14 Javascript
IE和Firefox之间在JavaScript语法上的差异
2016/04/22 Javascript
Ionic默认的Tabs模板使用实例
2016/08/29 Javascript
JS判断form内所有表单是否为空的简单实例
2016/09/09 Javascript
input框中的name和id的区别
2016/11/16 Javascript
JavaScript自动生成 年月范围 选择功能完整示例【基于jQuery插件】
2019/09/03 jQuery
React Native 混合开发多入口加载方式详解
2019/09/23 Javascript
微信小程序实现canvas分享朋友圈海报
2020/06/21 Javascript
JS中作用域以及变量范围分析
2020/07/18 Javascript
Python函数学习笔记
2008/10/07 Python
跟老齐学Python之dict()的操作方法
2014/09/24 Python
Python递归遍历列表及输出的实现方法
2015/05/19 Python
在Django同1个页面中的多表单处理详解
2017/01/25 Python
Python生成数字图片代码分享
2017/10/31 Python
解决pycharm无法调用pip安装的包问题
2018/05/18 Python
pandas去重复行并分类汇总的实现方法
2019/01/29 Python
Python实现的排列组合、破解密码算法示例
2019/04/12 Python
Python socket处理client连接过程解析
2020/03/18 Python
谈谈python垃圾回收机制
2020/09/27 Python
几款主流好用的富文本编辑器(所见即所得常用编辑器)介绍
2021/03/17 Javascript
德国药房apodiscounter中文官网:德国排名前三的网上药店
2019/06/03 全球购物
Delphi软件工程师试题
2013/01/29 面试题
2015年加油站工作总结
2015/05/13 职场文书
四年级作文之说明文作文
2019/10/14 职场文书
mysql分组后合并显示一个字段的多条数据方式
2022/01/22 MySQL