详解JavaScript几种跨域方式总结
本文详细总结了JavaScript中常见的跨域解决方案,涵盖window.name、动态Script标签、JSONP、document.domain、CORS、postMessage及location.hash等机制。通过对比各方案的原理、适用场景及代码示例,帮助开发者根据实际需求选择最合适的跨域通信方式,解决浏览器同源策略限制。
跨域背景与同源策略
在JavaScript等客户端编程语言中,浏览器遵循同源策略,规定不同域之间的脚本相互隔离,禁止一个域的脚本访问或操作另一个域的大部分属性和方法。只有当两个域拥有相同的协议、主机名和端口号时,才被视为同源。然而在实际开发中,获取其他域资源的需求十分常见,因此出现了多种跨域解决方案。本文将总结工作中常用的几种跨域方式,供后续查阅参考。
window.name跨域方案
1. window.name
window对象的name属性具有特殊性,当在iframe中加载新页面时,该属性的值保持不变。利用这一特性,可以在页面A中通过iframe加载其他域的页面B,并在页面B中将需要传递的数据赋值给window.name。当iframe加载完成后,即可获取该值以访问远程Web服务发送的信息。需要注意的是,name属性仅对相同域名的frame可访问。因此,在远程页面加载后,必须将iframe的地址导航回原始域,以便读取window.name的值。获取数据后,销毁该iframe即可。这种方式适合单向数据请求,具有协议简单、安全性较高的特点。
页面B(www.jesse.com/data.html)代码如下:
<script type="text/javascript">
window.name = 'I was there!';
// 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右
// 数据格式可以自定义,如json、字符串
</script>
页面A(www.jack.com/index.html)代码如下:
<script type="text/javascript">
var state = 0,
iframe = document.createElement('iframe'),
loadfn = function() {
if (state === 1) {
var data = iframe.contentWindow.name; // 读取数据
console.log(data); //弹出'I wasthere!'
(function(){
//获取数据以后销毁这个iframe。
iframe.contentWindow.document.write('');
iframe.contentWindow.close();
document.body.removeChild(iframe);
})();
} else if (state === 0) {
state = 1;
// 设置的代理页面使其回原始域
iframe.contentWindow.location = "http://www.jack.com/proxy.html";
}
};
iframe.src = 'http://www.jesse.com/data.html';
if (iframe.attachEvent) {
iframe.attachEvent('onload', loadfn);
} else {
iframe.onload = loadfn;
}
document.body.appendChild(iframe);
</script>
基于src属性的跨域通信
2. 具备src属性的标签
尽管浏览器默认禁止跨域访问,但允许通过标签的src属性引用其他域的文件。基于此原理,可以通过创建具有src属性的节点来实现完全跨域的通信。以下是几种利用该原理的跨域方式:
动态创建script
例如,若要从域A的页面pageA加载域B的数据,可以在域B的页面pageB中以JavaScript形式声明pageA所需的数据。随后,在pageA中使用script标签加载pageB,这样pageB中的脚本即可执行,从而实现数据交互。
pageA(www.jack.com/index.html)代码如下:
function getData(data){
//这里是对获取的数据的相关操作
console.log(data);
//数据获取到后移除创建的script标签
document.body.removeChild(originData);
}
var originData = document.createElement('script');
originData.src = 'http://www.jesse.com/data.js';
originData.setAttribute("type", "text/javascript");
document.body.appendChild(originData);
pageB(www.jesse.com/data.js)代码如下:
getData('这里是远程跨域获取的数据');//数据格式可以自定义,如json、字符串
jsonp
在使用$.ajax()获取远程数据时,若涉及跨域资源,可使用jsonp方法。此前常误认为jsonp是ajax的一种,但实际上二者原理不同:ajax基于xhr请求数据,而jsonp基于script标签请求数据,这与上述动态创建script的方式原理一致。
pageA(www.jack.com/index.html)代码如下:
$.ajax({
//JSONP不支持POST方式
type:"GET",
url:"http://www.jesse.com/data.php",
dataType:"jsonp",
//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
jsonpCallback:"getData",
success: function(data){
console.log(data);
},
error: function(){
console.log('fail');
}
})
pageB(www.jesse.com/data.js)代码如下:
<?php
$callback = $_GET['callback'];//得到回调函数名,这里是getData
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>
document.domain跨域方案
3. document.domain
对于主域相同但子域不同的情况,可以通过设置document.domain来解决跨域问题。具体做法是在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别设置document.domain = "a.com"。随后,通过a.html中创建iframe并控制其contentDocument,实现两个js文件之间的交互。需要注意的是,该方法仅适用于主域相同且二级域名不同的场景。
www.a.com上的a.html
document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){
var doc = ifr.contentDocument || ifr.contentWindow.document;
// 在这里操纵b.html
alert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};
script.a.com上的b.html
document.domain = 'a.com';
CORS跨域资源共享
4. 跨域资源共享(CORS)
原理:跨源资源共享(CORS)定义了一种跨域访问机制,使AJAX能够实现跨域请求。CORS允许一个域上的网络应用向另一个域提交跨域AJAX请求。实现过程相对简单,只需服务器发送响应标头即可。该机制通过客户端与服务端协作声明来确保请求安全。服务端在HTTP响应头中增加一系列参数(如Access-Control-Allow-Origin等),以限制允许请求的域和请求类型;客户端在发起请求时必须声明自己的源(Origin),否则服务器将不予处理,甚至浏览器会直接拦截请求。服务端收到请求后进行域比较,仅处理同域请求。
pageA(www.jack.com/index.html)代码如下:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
console.log(xhr.responseText);
}
};
xhr.open("get","http://www.jesse.com/data.php");
xhr.send(null);
pageB(www.jesse.com/data.php)代码如下:
<?php
header("Access-Control-Allow-Origin: http://www.jack.com");//与简单的请求相同
header("Access-Control-Allow-Methods: GET, POST");//允许请求的方法
header("Access-Control-Max-Age: 3628800"); //将这个请求缓存多长时间
$data = array('a','b','c');//要返回的数据
echo json_encode($data);//输出
?>
其他跨域方式
5. window.postMessage(不常用)
window.postMessage(message,targetOrigin)是HTML5引入的新特性,用于向其他window对象发送消息,无论目标窗口是否同源。目前IE8+、Firefox、Chrome、Opera等主流浏览器均已支持该方法。
pageA(www.jack.com/index.html)代码如下:
<iframe id="proxy" src="http://www.jesse.com/index.html" onload="postMsg()" style="display: none"></iframe>
<script type="text/javascript">
var obj = {
msg: 'hello world'
}
function postMsg() {
var iframe = document.getElementById('proxy');
var win = iframe.contentWindow;
win.postMessage(obj, 'http://www.jesse.com');
}
</script>
pageB(www.jesse.com/data.php)代码如下:
<script type="text/javascript">
window.onmessage = function(e) {
console.log(e.data.msg + " from " + e.origin);
}
</script>
6. location.hash(不常用)
pageA(www.jack.com/index.html)代码如下:
function startRequest() {
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://www.jesse.com/b.html#sayHi'; //传递的location.hash
document.body.appendChild(ifr);
}
function checkHash() {
try {
var data = location.hash ? location.hash.substring(1) : '';
if (console.log) {
console.log('Now the data is ' + data);
}
} catch (e) {};
}
setInterval(checkHash, 5000);
window.onload = startRequest;
pageA(www.jack.com/proxy.html)代码如下:
parent.parent.location.hash = self.location.hash.substring(1);
pageB(www.jesse.com/b.html)代码如下:
function checkHash() {
var data = '';
//模拟一个简单的参数处理操作
switch (location.hash) {
case '#sayHello':
data = 'HelloWorld';
break;
case '#sayHi':
data = 'HiWorld';
break;
default:
break;
}
data && callBack('#' + data);
}
function callBack(hash) {
// ie、chrome的安全机制无法修改parent.location.hash,所以要利用一个中间的www.a.com域下的代理iframe
var proxy = document.createElement('iframe');
proxy.style.display = 'none';
proxy.src = 'http://www.jack/c.html' + hash; // 注意该文件在"www.jack.com"域下
document.body.appendChild(proxy);
}
window.onload = checkHash;
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
什么时候该用JS构造器:与工厂模式、字面量的选择对比
2026-11-05 16:18:22
推荐几款轻量级JS照片墙开源库及对比
2026-11-05 15:56:19
JavaScript递归写法有哪些常见陷阱及避免方法
2026-11-05 14:53:38
JS数组浅拷贝与深拷贝怎么选?场景与方法总结
2026-11-05 14:41:02
p5.js 中 setup() 和 draw() 函数的执行机制详解
2026-11-05 12:32:38
