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基本语法分析说明
Jun 15 Javascript
JS 用6N±1法求素数 实例教程
Oct 20 Javascript
用按钮控制iframe显示的网页实现方法
Feb 04 Javascript
利用JS生成博文目录及CSS定制博客
Feb 10 Javascript
Jquery插件仿百度搜索关键字自动匹配功能
May 11 Javascript
jQuery中ScrollTo用法示例
Sep 04 Javascript
JS实现页面进入和返回定位到具体位置
Dec 08 Javascript
Ajax跨域实现代码(后台jsp)
Jan 21 Javascript
JS正则表达式常见用法实例详解
Jun 19 Javascript
详解Axios 如何取消已发送的请求
Oct 20 Javascript
JavaScript 判断iPhone X Series机型的方法
Jan 28 Javascript
详解vue身份认证管理和租户管理
May 25 Vue.js
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
ecshop实现smtp发送邮件
2015/02/03 PHP
PHP使用Pthread实现的多线程操作实例
2015/11/14 PHP
phpcms中的评论样式修改方法
2016/10/21 PHP
老生常谈PHP面向对象之解释器模式
2017/05/17 PHP
详解php实现页面静态化原理
2017/06/21 PHP
Jquery实现列表(隔行换色,全选,鼠标滑过当前行)效果实例
2013/06/09 Javascript
点击表单提交时出现jQuery没有权限的解决方法
2014/07/23 Javascript
jQuery中prependTo()方法用法实例
2015/01/08 Javascript
jQuery 利用$.ajax 时获取原生XMLHttpRequest 对象的方法
2016/08/25 Javascript
vue-axios使用详解
2017/05/10 Javascript
详解nodejs中express搭建权限管理系统
2017/09/15 NodeJs
微信小程序使用checkbox显示多项选择框功能【附源码下载】
2017/12/11 Javascript
基于vue-element组件实现音乐播放器功能
2018/05/06 Javascript
JavaScript递归函数解“汉诺塔”算法代码解析
2018/07/05 Javascript
Vue动态加载异步组件的方法
2018/11/21 Javascript
详解nodejs解压版安装和配置(带有搭建前端项目脚手架)
2018/12/06 NodeJs
vue实现鼠标移入移出事件代码实例
2019/03/27 Javascript
微信小程序遍历Echarts图表实现多个饼图
2019/04/25 Javascript
浅谈Vue项目骨架屏注入实践
2019/08/05 Javascript
[42:27]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第三局
2016/03/05 DOTA
[46:04]Liquid vs VP Supermajor决赛 BO 第四场 6.10
2018/07/05 DOTA
python复制与引用用法分析
2015/04/08 Python
详解在Python中处理异常的教程
2015/05/24 Python
flask框架路由常用定义方式总结
2019/07/23 Python
python实现视频读取和转化图片
2019/12/10 Python
Python selenium模拟手动操作实现无人值守刷积分功能
2020/05/13 Python
纯CSS3实现鼠标滑过按钮动画第二节
2020/07/16 HTML / CSS
世界上最大的在线旅行社新加坡网站:Expedia新加坡
2016/08/25 全球购物
波兰品牌内衣及泳装网上商店:Astratex.pl
2017/02/03 全球购物
SmartBuyGlasses德国:购买太阳镜和眼镜
2019/08/20 全球购物
应届生体育教师自荐信
2013/10/03 职场文书
新闻系毕业生推荐信
2013/11/16 职场文书
大学军训感言800字
2014/02/27 职场文书
安全承诺书范文
2014/03/26 职场文书
国博复兴之路观后感
2015/06/02 职场文书
中秋节主题班会
2015/08/14 职场文书