JS跨域问题详解


Posted in Javascript onNovember 25, 2014

JavaScript是一种在Web开发中经常使用的前端动态脚本技术。在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。

JavaScript这个安全策略在进行多iframe或多窗口编程、以及Ajax编程时显得尤为重要。根据这个策略,在baidu.com下的页面中包含的JavaScript代码,不能访问在google.com域名下的页面内容;甚至不同的子域名之间的页面也不能通过JavaScript代码互相访问。对于Ajax的影响在于,通过XMLHttpRequest实现的Ajax请求,不能向不同的域提交请求,例如,在abc.example.com下的页面,不能向def.example.com提交Ajax请求,等等。

然而,当进行一些比较深入的前端编程的时候,不可避免地需要进行跨域操作,这时候“同源策略”就显得过于苛刻。本文就这个问题,概括了跨域所需要的一些技术。

下面我们分两种情况讨论跨域技术:首先讨论不同子域的跨域技术,然后讨论完全不同域的跨域技术。

(一)不同子域的跨域技术。

我们分两个问题来分别讨论:第一个问题是如何跨不同子域进行JavaScript调用;第二个问题是如何向不同子域提交Ajax请求。

先来解决第一个问题,假设example.com域下有两个不同子域:abc.example.com和def.example.com。现在假设在def.example.com下面有一个页面,里面定义了一个JavaScript函数:

function funcInDef() {

   .....

}

我们想在abc.example.com下的某个页面里调用上面的函数。再假设我们要讨论的abc.example.com下面的这个页面是以iframe形式嵌入在def.example.com下面那个页面里的,这样我们可能试图在iframe里做如下调用:

window.top.funcInDef();

 

好,我们注意到,这个调用是被前面讲到的“同源策略”所禁止的,JavaScript引擎会直接抛出一个异常。

为了实现上述调用,我们可以通过修改两个页面的domain属性的方法做到。例如,我们可以将上面在abc.example.com和def.example.com下的两个页面的顶端都加上如下的JavaScript代码片段:

<script type="text/javascript">

    document.domain = "example.com";

</script>

这样,两个页面就变为同域了,前面的调用也可以正常执行了。

这里需要注意的一点是,一个页面的document.domain属性只能设置成一个更顶级的域名(除了一级域名),但不能设置成比当前域名更深层的子域名。例如,abc.example.com的页面只能将它的domain设置成example.com,不能设置成sub.abc.example.com,当然也不能设置成一级域名com。

上面的例子讨论的是两个页面属于iframe嵌套关系的情况,当两个页面是打开与被打开的关系时,原理也完全一样。

下面我们来解决第二个问题:如何向不同子域提交Ajax请求。

通常情况下,我们会用与下面类似的代码来创建一个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 <</SPAN> 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,例如:

[code]

<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请求了。

(二)完全不同域的跨域技术。

如果顶级域名都不相同,例如example1.com和example2.com之间想通过JavaScript在前端通信,则所需要的技术更复杂些。

在讲解不同域的跨域技术之前,我们首先明确一点,下面要讲的技术也同样适用于前面跨不同子域的情况,因为跨不同子域只是跨域问题的一个特例。当然,在恰当的情况下使用恰当的技术,能够保证更优的效率和更高的稳定性。

简言之,根据不同的跨域需求,跨域技术可以归为下面几类:

1、JSONP跨域GET请求
2、通过iframe实现跨域
3、flash跨域HTTP请求
4、window.postMessage

本文先到这里,后续我们再详细介绍上面提到的4种跨域技术,稍后就奉上!

Javascript 相关文章推荐
javascript高亮效果的二种实现方法
Sep 14 Javascript
jquery原创弹出层折叠效果点击折叠弹出一个层
Mar 12 Javascript
js实现精美的银灰色竖排折叠菜单
May 16 Javascript
JavaScript中实现map功能代码分享
Jun 11 Javascript
JavaScript+html5 canvas制作色彩斑斓的正方形效果
Jan 27 Javascript
ES6中的数组扩展方法
Aug 26 Javascript
AngularJS自定义插件实现网站用户引导功能示例
Nov 07 Javascript
详解Node.js模板引擎Jade入门
Jan 19 Javascript
vue v-model动态生成详解
Jun 30 Javascript
详解vue.js移动端配置flexible.js及注意事项
Apr 10 Javascript
vue页面加载时的进度条功能(实例代码)
Jan 13 Javascript
JavaScript 替换所有匹配内容及正则替换方法
Feb 12 Javascript
javascript 中__proto__和prototype详解
Nov 25 #Javascript
js 加密压缩出现bug解决方案
Nov 25 #Javascript
js Object2String方便查看js对象内容
Nov 24 #Javascript
js的[defer]和[async]属性
Nov 24 #Javascript
使用JavaScript 编写简单计算器
Nov 24 #Javascript
JS和JQ的event对象区别分析
Nov 24 #Javascript
JavaScript实现大数的运算
Nov 24 #Javascript
You might like
php通用防注入程序 推荐
2011/02/26 PHP
PHP 闭包详解及实例代码
2016/09/28 PHP
提高代码性能技巧谈—以创建千行表格为例
2006/07/01 Javascript
js二维数组定义和初始化的三种方法总结
2014/03/03 Javascript
高性能JavaScript DOM编程(1)
2015/08/11 Javascript
简单实现限制uploadify上传个数
2015/11/16 Javascript
详解javascript事件冒泡
2016/01/09 Javascript
详解Matlab中 sort 函数用法
2016/03/20 Javascript
非常酷炫的Bootstrap图片轮播动画
2016/05/27 Javascript
javascript比较语义化版本号的实现代码
2016/09/09 Javascript
JS简单验证上传文件类型的方法
2017/04/17 Javascript
node使用promise替代回调函数
2018/05/07 Javascript
解决layer弹层遮罩挡住窗体的问题
2018/08/17 Javascript
JS二级菜单不同实现方法分析【4种方法】
2018/12/21 Javascript
Vue基础学习之项目整合及优化
2019/06/02 Javascript
JS中的算法与数据结构之二叉查找树(Binary Sort Tree)实例详解
2019/08/16 Javascript
Vue 解决路由过渡动画抖动问题(实例详解)
2020/01/05 Javascript
[02:42]岂曰无衣,与子同袍!DOTA2致敬每一位守护人
2020/02/17 DOTA
Python实现将MySQL数据库表中的数据导出生成csv格式文件的方法
2018/01/11 Python
Python内存读写操作示例
2018/07/18 Python
详解配置Django的Celery异步之路踩坑
2018/11/25 Python
对Python中 \r, \n, \r\n的彻底理解
2020/03/06 Python
Python ORM框架Peewee用法详解
2020/04/29 Python
浅谈对python中if、elif、else的误解
2020/08/20 Python
Kidsroom台湾:来自德国的婴儿用品
2017/12/11 全球购物
第一范式(1NF)、第二范式(2NF)和第三范式(3NF)之间的区别是什么?
2016/04/28 面试题
优秀研究生自我鉴定
2013/12/04 职场文书
主持人演讲稿范文
2013/12/28 职场文书
《可爱的动物》教学反思
2014/02/22 职场文书
航海技术专业毕业生推荐信
2014/07/09 职场文书
“四风”问题整改措施和努力方向
2014/09/20 职场文书
机关作风建设剖析材料
2014/10/11 职场文书
2014年教师思想工作总结
2014/12/03 职场文书
信用卡工资证明范本
2015/06/19 职场文书
公司员工离职感言
2015/08/03 职场文书
怎么用Python识别手势数字
2021/06/07 Python