JavaScript跨域解决方案:子域与完全跨域技术详解
本文深入解析JavaScript的同源策略限制,详细阐述不同子域间通过修改document.domain实现跨域调用的方法,以及完全跨域场景下的JSONP、iframe、Flash和window.postMessage等技术原理与实现步骤。
JavaScript同源策略概述
JavaScript作为Web开发中广泛使用的前端动态脚本技术,受到“Same-Origin Policy”(同源策略)这一重要安全机制的约束。该策略严格限制了JavaScript代码可访问的页面内容,规定脚本仅能读取与包含它的文档处于同一域下的资源。
在涉及多iframe或多窗口编程,以及Ajax异步请求的场景中,同源策略的作用尤为关键。依据此策略,位于baidu.com域下的页面脚本无法访问google.com域下的页面内容,甚至不同子域名之间的页面也无法通过JavaScript相互访问。对于Ajax而言,这意味着通过XMLHttpRequest发起的请求不能指向不同的域,例如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引擎会直接抛出异常。
为了实现上述调用,我们可以通过修改两个页面的document.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种跨域技术,稍后就奉上!
Object.assign合并JS对象的用法与注意事项
2026-11-05 17:56:08
JS大数值转字符串出现科学计数法怎么办
2026-11-05 17:09:21
JS split切割后出现空字符串怎么过滤
2026-11-05 16:00:30
在 React 或 Vue 项目中封装使用 JS 节流防抖
2026-11-05 15:27:29
JavaScript中怎么将带小数的字符串转为整数?
2026-11-05 14:32:38
