1 同源策略
同源策略,是由网景(netscape)提出的一个著名的安全策略,现在所有的浏览器都会使用这一安全策略。所谓同源策略,即相互访问的页面之间必须具有相同的协议、端口和主机地址。
下表给出了相对http://store.company.com/dir/page.html同源检测的结果。
由于同源策略的限制,不同域名之间无法通过HTTP请求相互访问。我们把不同域名之间的访问问题称为跨域问题。
2 常用的跨域方法
本部分主要介绍当前主流的几种跨域方法,包括Cors、JSONP、window.name等几种常见的跨域方法。
本部分实验部分包括两台服务器,两台服务器ip地址不同,设置的域名分别为fe.xiaojukeji.com(主服务器)、fe_vm.xiaojukeji.com(从
服务器)。
2-1 Cors(Cross-origin resource sharing)
CORS全称为Cross-origin resource sharing,是一个W3C标准。CORS定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS 允许一
个域上的网络应用向另一个域提交跨域 AJAX 请求。CORS需要浏览器和服务器同时支持。目前只有Opera Mini和IE10以下不支持。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通
信。
CORS有两种请求:简单请求(Simple requests)和预检请求(Preflighted requests),以下部分根据原理图分析介绍CORS的两种请求。
简单请求
满足下列条件就称为简单请求:
- 请求方法
- GET
- POST
- HEAD
- 允许设置头部标识(除了用户代理)
- Accept
- Accept-Language
- Content-Langugae
- Content-Type
- 允许的Content-Type标识头
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
例如,我们从主服务器(fe.xiaojukeji.com)向从服务器(fe_vm.xiaojukeji.com)发送AJAX请求,如下:
主服务器代码
var xmlhttp = new XMLHttpRequest();
var url = 'http://fe_vm.xiaojukeji.com/CORS/cors.php';
function callOtherDomain() {
if(xmlhttp) {
xmlhttp.open('GET', url, true);
xmlhttp.onreadystatechange = handler;
xmlhttp.send();
}
}
function handler(){
if(xmlhttp.readyState == 4) {
if(xmlhttp.status == 200) {
var response = xmlhttp.responseText;
var divresult = document.getElementById("result");
divresult.innerHTML = response;
}
}
}
callOtherDomain();
从服务器httpd.conf配置文件,可以接受http://fe.xiaojukeji.com的跨域访问,修改如下:
<Directory />
Options FollowSymLinks
AllowOverride None
Header set Access-Control-Allow-Origin http://fe.xiaojukeji.com
</Directory>
从服务器cors.php代码
header("Access-Control-Allow-Origin:http://fe.xiaojukeji.com");
$return = array(
'login' => 'admin',
'pass' => '12345'
);
echo json_encode($return);
浏览器发送跨域AJAX请求,Ajax响应数据如下:
- 响应结果
Request URL:http://fe_vm.xiaojukeji.com/CORS/cors.php
Request Method:GET
Status Code:200 OK
Remote Address:*(此处为从服务器IP):80- 响应头部
Access-Control-Allow-Origin:http://fe.xiaojukeji.com
Connection:close
Content-Length:32
Content-Type:text/html; charset=UTF-8
Date:Wed, 24 Aug 2016 06:57:49 GMT
Server:Apache/2.2.15 (CentOS)
X-Powered-By:PHP/5.3.3- 请求头部
Accept:/
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Host:fe_vm.xiaojukeji.com
Origin:http://fe.xiaojukeji.com
Referer:http://fe.xiaojukeji.com/CORS/cors_simpleRequest.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
Ajax响应数据为在Chrome浏览器的响应结果,请求头部中Origin表示发送Cors请求的源域,host为跨域的目的域。响应头部中Access-Contr
ol-Allow-Origin表示允许http://fe.xiaojukeji.com域名进行跨域访问。
如下图,返回结果已经显示在页面中。
预检请求
预检请求收先会发送一次包含某些选项头的OPTIONS请求,已确认是否能否安全传送。预符合下面情况的就会被当做预检请求:
- 使用GET、HEAD或者POST以外的请求方法。
- 使用POST向服务器端传送数据时,数据类型(Content-Type)为application/x-www-form-urlencoded、multipart/form-data、text/plain三种以外类型。
- 使用了自定义请求头。
例如,我们从主服务器(fe.xiaojukeji.com)向从服务器(fe_vm.xiaojukeji.com)发送含有自定义选项的POST请求,如下:
主服务器代码
var xmlhttp = new XMLHttpRequest();
var url = 'http://fe_vm.xiaojukeji.com/CORS/cors2.php';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
if(xmlhttp)
{
xmlhttp.open('POST', url, true);
xmlhttp.setRequestHeader('X-PINGOTHER', 'pingpong');
xmlhttp.setRequestHeader('Content-Type', 'application/xml');
xmlhttp.onreadystatechange = handler;
xmlhttp.send(body);
}
}
function handler(){
if(xmlhttp.readyState == 4) {
if(xmlhttp.status == 200) {
var response = xmlhttp.responseText;
var divresult = document.getElementById("result");
divresult.innerHTML = response;
}
}
}
callOtherDomain();
从服务器代码
header("Access-Control-Allow-Origin:http://fe.xiaojukeji.com");
header('Access-Control-Allow-Methods:POST');
header('Access-Control-Allow-Headers:x-pingother,content-type');
header("Content-Type:application/xml");
$return = array(
'login' => 'admin',
'pass' => '12345'
);
echo json_encode($return);
浏览器发送跨域AJAX请求,Ajax响应数据如下:
- 第一次请求:options请求
- 响应结果
Request URL:http://fe_vm.xiaojukeji.com/CORS/cors2.php
Request Method:OPTIONS
Status Code:200 OK
Remote Address:*(此处为从服务器IP):80- 响应头部
Access-Control-Allow-Headers:x-pingother,content-type
Access-Control-Allow-Methods:POST
Access-Control-Allow-Origin:http://fe.xiaojukeji.com
Connection:close
Content-Length:32
Content-Type:application/xml
Date:Wed, 24 Aug 2016 08:17:02 GMT
Server:Apache/2.2.15 (CentOS)
X-Powered-By:PHP/5.3.3- 请求头部
Accept:/
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Access-Control-Request-Headers:content-type, x-pingother
Access-Control-Request-Method:POST
Cache-Control:max-age=0
Connection:keep-alive
Host:fe_vm.xiaojukeji.com
Origin:http://fe.xiaojukeji.com
Referer:http://fe.xiaojukeji.com/CORS/cors_preflightedRequests.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36- 第二次请求:AJAX POST 请求
- 响应结果
Request URL:http://fe_vm.xiaojukeji.com/CORS/cors2.php
Request Method:POST
Status Code:200 OK
Remote Address:10.94.104.114:80- 响应头部
Access-Control-Allow-Headers:x-pingother,content-type
Access-Control-Allow-Methods:POST
Access-Control-Allow-Origin:http://fe.xiaojukeji.com
Connection:close
Content-Length:32
Content-Type:application/xml
Date:Wed, 24 Aug 2016 08:17:02 GMT
Server:Apache/2.2.15 (CentOS)
X-Powered-By:PHP/5.3.3- 请求头部
Accept:/
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Connection:keep-alive
Content-Length:55
Content-Type:application/xml
Host:fe_vm.xiaojukeji.com
Origin:http://fe.xiaojukeji.com
Referer:http://fe.xiaojukeji.com/CORS/cors_preflightedRequests.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
X-PINGOTHER:pingpong
第一次请求为OPTIONS请求,表示这个请求是用来询问的。请求头信息有三个关键点:
(1)Origin为http://fe.xiaojukeji.com,表示请求来自的源。
(2)Access-Control-Request-Method,表示请求的方法为POST方法。
(3)Access-Control-Request-Headers表示请求发送的附加信息头字段,例中附加信息头为content-type、x-pingother。
第一次请求的响应头部中,Access-Control-Allow-Origin为“http://fe.xiaojukeji.com”,表示同意“http://fe.xiaojukeji.com
”域名下的跨域请求。
第二次请求为POST请求,用来发送正式的请求。第二次请求与简单请求是类似的。这里就不赘述。
附带凭证请求
默认情况下,在跨域发送AJAX请求,浏览器是不会发送Cookie和HTTP身份凭证信息的,若果需要发送附带Cookie和HTTP身份凭证信息,则需要
设置XMLHttpRequest的withCredentials属性。
如下所示的例子,主服务器向从服务器发送Ajax发送Get请求,并设置withCredentials属性,传递Cookie。
主服务器代码
var xmlhttp = new XMLHttpRequest();
var url = 'http://fe_vm.xiaojukeji.com/CORS/cors3.php';
function callOtherDomain() {
if(xmlhttp) {
xmlhttp.open('GET', url, true);
xmlhttp.withCredentials = true;
xmlhttp.onreadystatechange = handler;
xmlhttp.send();
}
}
function handler(){
if(xmlhttp.readyState == 4) {
if(xmlhttp.status == 200) {
var response = xmlhttp.responseText;
var divresult = document.getElementById("result");
divresult.innerHTML = response;
}
}
}
callOtherDomain();
从服务器代码
header("Access-Control-Allow-Origin:http://fe.xiaojukeji.com");
header("Access-Control-Allow-Credentials: true");
$return = array(
'login' => 'admin',
'pass' => '12345'
);
echo json_encode($return);
浏览器发送跨域AJAX请求,Ajax响应数据如下:
- 响应结果
Request URL:http://fe_vm.xiaojukeji.com/CORS/cors3.php
Request Method:GET
Status Code:200 OK
Remote Address:10.94.104.114:80- 响应头部
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://fe.xiaojukeji.com
Connection:close
Content-Length:32
Content-Type:text/html; charset=UTF-8
Date:Wed, 24 Aug 2016 09:39:43 GMT
Server:Apache/2.2.15 (CentOS)
X-Powered-By:PHP/5.3.3- 请求头部
Accept:/
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8,en;q=0.6
Cache-Control:max-age=0
Connection:keep-alive
Cookie:uccap=”MTQ3MjAyOTExNjgzMw==”; ucauth_q2=”bGlqaW5jYWk=”; carrenttoken=bGlqaW5jYWkxNDcyMDI5MTIwNDk3; cityId=59; supplierId=24
Host:fe_vm.xiaojukeji.com
Origin:http://fe.xiaojukeji.com
Referer:http://fe.xiaojukeji.com/CORS/cors_requestsWithCredentials.html
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36
请求头部中有传递的Cookie值,响应头部中Access-Control-Allow-Credentials: true。一般情况下,ajax请求中必须打开withCred-
entials属性,服务端也必须设置Access-Control-Allow-Credentials:true。两者必须全部设定,否则会发生跨域的错误。
如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同
源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器
域名下的Cookie(本部分引用于跨域资源共享CORS详解)。
相关HTTP响应头
Access-Control-Allow-Origin: Orgin | *
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
Access-Control-Max-Age: delta-seconds
Access-Control-Allow-Credentials: true|false
Access-Control-Allow-Methods:method[, method]*
Access-Control-Allow-Headers: field-name[, field-name]*
相关HTTP请求头
Origin: origin
Access-Control-Request-Method: method
Access-Control-Allow-Headers: field-name[, field-name]*
2-2 JSONP(JSON with Padding)
JSONP(JSON with Padding)是一个非官方的协议,它允许在服务器端集成Scripttags返回至客户端,通过javascript callback的形式实现跨域访问。
jsonp的应用基础是script标签中的外部js函数是可以被执行或者调用的。如常用引用<script src="//cdn.bootcss.com/jquery/3.1.0
/jquery.js" ></script>,我们可以调用jquery的相关函数。
依据实例给出JSONP的客户端具体实现(本部分的思路与链接9思路相同,感觉链接9作者提供的思路):
(1) 远程调用JS,执行跨域中JS的代码。
本部分主要说明跨域中的JS函数是可以调用的。
主服务器代码
var localHandler = function(data){
alert('我是主服务器上函数,从服务器的数据是:' + data.result);
};
从服务器代码
localHandler({"result":"我是从服务器上的数据!!"});
执行主服务器的html,得到执行结果如下:
页面成功弹出提示窗口,显示主服务器的远程js调用成功,并且还接收到了远程js带来的数据。现在面临的问题就是跨域服务器如何知道的call-
back函数。
(2)向跨域服务传递callback函数,要求跨域服务器返回需求的JS函数。
本部分主要通过原生JS完成JSONP协议。
主服务器代码
function jsonpCallback(result) {
var html = '';
for(var i in result) {
html += '<div><span>'+i+':</span><p>'+result[i]+'</p></div>';
}
console.log(html);
document.getElementById('showTips').innerHTML = html;
}
var JSONP=document.createElement("script");
JSONP.type="text/javascript";
JSONP.src="http://fe_vm.xiaojukeji.com/jsonp/jsonp.php?jsoncallback=jsonpCallback";
document.getElementsByTagName("head")[0].appendChild(JSONP);
从服务器代码
header('Content-Type:text/html;Charset=utf-8');
$arr = array(
"user" => 'admin',
"pass" => '123456'
);
echo $_GET['jsoncallback'] . "(".json_encode($arr).")";
主服务器中,向从服务器发送GET请求,请求的返回函数为jsoncallback。从服务器后端代码使用php函数获取函数名称定义$_GET['jsonca-
llback']函数,传递的数据为json_encode($arr)。HTTP请求完成后,jsonpCallback函数执行,执行后showTips,显示返回数据内容。
执行结果如下
(3)JQuery JSONP跨域
本部分主要介绍jquery的jsonp跨域方法
JQuery将JSONP协议集合与AJAX请求中,极大方便了我们的前端开发。
主服务器代码
$(function(){
$.ajax(
{
type:'get',
url : 'http://fe_vm.xiaojukeji.com/jsonp/jsonp.php',
dataType : 'jsonp',
data:{
loginuser: "admin",
loginpass: "123456"
},
jsonp:"jsoncallback",
success : function(data) {
var html = "<div>用户名:"+ data.user+"</div>";
html += "<div>密码:"+ data.pass+"</div>";
$("#showTips").html(html);
},
error : function() {
$("#showTips").html('error connect!');
}
}
);
});
从服务器代码
header('Content-Type:text/html;Charset=utf-8');
$arr = array(
"user" => 'admin',
"pass" => '123456'
);
echo $_GET['jsoncallback'] . "(".json_encode($arr).")";
主服务器中并未定义jsoncallback,但是仍然能执行,这主要是因为jquery将jsonp归入了ajax,自动帮你生成回调函数并把数据取出来供
success属性方法来调用。
2-3 window.name
Window.name属性的优势在于:name值在不同的页面加载后依然存在且支持非常长的name值(2MB)。
由于window.name存在时间及可访问性,window.name可被用于页面信息的传递及跨域信息的传递中。下图为window.name的传输原理,依据
此原理图,window.name的传输技术的基本原理和步骤如下:
(1)客户机浏览器创建隐藏iframe,加载跨域站点,跨域站点设置window.name=传递信息。
(2)客户机监控onload事件,iframe站点加载完成后,由于无法访问跨域的iframe,此时需要设置iframe,返回到客户机的原始域中。
(3)返回到原始域中,触发新的onload事件,解析获取得到传输的data数据,并且删除添加的iframe,完成一次信息的传输。
本文按照链接9的思路做了相关的实验,验证window.name实现跨域。
主服务器代码
(function(){
dataRequest = {
_doc: document,
cfg: {
proxyUrl: 'http://fe.xiaojukeji.com/WINDOWNAME/windowName.html'
}
};
//surl 跨域的url,fnCallBack回调函数
dataRequest.send = function(sUrl, fnCallBack){
if(!sUrl || typeof sUrl !== 'string'){
return;
}
sUrl += (sUrl.indexOf('?') > 0 ? '&' : '?') + 'windowname=true';
var frame = this._doc.createElement('iframe'), state = 0, self = this;
frame.id = 'iframe';
this._doc.body.appendChild(frame);
frame.style.display = 'none';
//删除添加的iframe
var clear = function(){
try{
frame.contentWindow.document.write('');
frame.contentWindow.close();
self._doc.body.removeChild(frame);
}catch(e){}
};
//获取数据
var getData = function(){
try{
var da = frame.contentWindow.name;
}catch(e){}
clear();
if(fnCallBack && typeof fnCallBack === 'function'){
fnCallBack(da);
}
};
//onload事件
document.getElementById('iframe').onload = function(){
if(state === 1){
getData();
} else if(state === 0){
state = 1;
frame.contentWindow.location = self.cfg.proxyUrl;
}
};
frame.src = sUrl;
};
})();
function callback(da){
document.getElementById('showTips').innerHTML = da;
}
var crossUrl ='http://fe_vm.xiaojukeji.com/windowName/window_name.html'
var dataRequest2 = dataRequest.send(crossUrl,callback);
从服务器代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>window.name测试</title>
</head>
<body>
<p id="htmlContent">
some <strong>html/xml-style</strong>data
</p>
</body>
<script type="text/javascript">
//普通字符串
window.name = "我是从服务器数据,现在传递给主服务器";
//XML/HTML数据
window.name = document.getElementById("htmlContent").innerHTML;
//JSON
var temp= {
foo:"bar",
baz:"foo"
};
window.name = JSON.stringify(temp);
</script>
</html>
执行结果
window.name可以实String、JSON和HTML/XML数据的传递。跨域的HTML(从服务器)window.name设置的值,主服务器在切换到自身域后,
可以调用读取window.name,从而实现跨域的信息传递。
2-4 HTML5 postMessage和onMessage
在 HTML5 中提出了工作线程(Web Workers)的概念,并且规范出 Web Workers的三大主要特征:能够长时间运行(响应),理想的启动性能以及理想的内存消耗。Web Workers 为 Web前端网页上的脚本提供了一种能在后台进程中运行的方法。一旦它被创建,Web Workers 就可以通过postMessage向任务池发送任务请求,执行完之后再通过 postMessage 返回消息给创建者指定的事件处理程序 ( 通过onmessage 进行捕获)(详情参见链接11)。
使用 postMessage和onMessage,不仅同源(域 + 端口号)的 Web 网页之间可以互相通信,甚至可以实现跨域通信。在接收窗口使用
onmessage 事件进行监听,发送窗口通过 postMessage 方法来传递数据。该方法使用两个参数:data、origin,data为发送的消息样本
、origin是可接受的窗口(*代表任何窗口都能接受)。
设计实验验证H5 postMessage可以实现跨域的消息传递(实验代码参照链接11)。
主服务器
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>使用H5实现跨域</title>
<script type="text/JavaScript">
function sendIt(){
// 通过 postMessage 向子窗口发送数据
document.getElementById("otherPage").contentWindow
.postMessage(
document.getElementById("message").value,
"http://fe_vm.xiaojukeji.com"
);
}
</script>
</head>
<body>
<!-- 通过 iframe 嵌入子页面 -->
<iframe src="http://fe_vm.xiaojukeji.com/h5Post/h5Post.html"
id="otherPage" style="width:100%;"></iframe>
<br/><br/>
<input type="text" id="message"><input type="button"
value="发送来自从服务器" onclick="sendIt()" />
</body>
</html>
从服务器代码
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Web page from child.com</title>
<script type="text/JavaScript">
//event 参数中有 data 属性,就是父窗口发送过来的数据
window.addEventListener("message", function( event ) {
// 把父窗口发送过来的数据显示在子窗口中
document.getElementById("content").innerHTML+=event.data+"<br/>";
}, false );
</script>
</head>
<body>
页面内容 http://fe_vm.xiaojukeji.com/h5Post/h5Post.html
<div id="content"></div>
</body>
</html>
实验结果
主服务器向子窗口发送PostMessage message信息,从服务器代码添加'message'的监控事件。一旦主服务器运行发送Message消息,从服务
域message接收主服务器发送的信息,从而完成跨域通信。
2-5 document.domain + iframe
相同主域名不同子域名下的页面,可以设置 document.domain 让它们同域,从而实现跨域通信。但是这种方法必须在主域名相同、域名协议和端口一致,否则无法实现跨域通信。
两个域名下页面需要交互时,如http://fe.xiaojukeji.com/DOMAIN/domain.html需要和http://fe_vm.xiaojukeji.com/domain/
domain_iframe.html页面进行通信前者通过添加iframe,设置两者的document.domain,完成两个页面的通信。
本文设计相关实验,验证主域名相同、协议与端口相同下,通过设置document.domain完成苦与通信。
主服务器代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>domain实现跨域</title>
<script type="text/javascript" src="jquery-1.7.1.js"></script>
<script type="text/javascript">
document.domain = "xiaojukeji.com"; //设置成主域
function testDomain(){
var win = document.getElementById('iframe').contentWindow,
doc = win.document,
content = doc.body;
document.getElementById('showTips').innerHTML = content.innerHTML;
}
</script>
</head>
<body>
<h1>iframe显示数据</h1>
<iframe src="http://fe_vm.xiaojukeji.com/domain/iframe.html" onload='testDomain()' id="iframe"></iframe>
<h1>获取iframe数据显示</h1>
<div class="divShow" id="showTips" style="border:solid 2px #FF2;">
</div>
</body>
</html>
从服务器代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>iframe实现跨域</title>
<script type="text/javascript">
document.domain = "xiaojukeji.com"
</script>
</head>
<body>
<h1>hello world!!!</h1>
</body>
</html>
实验结果
在主服务器、从服务器的页面中,我们都设置document.domain=“xiaojukeji.com”,从而使两个页面的域名相同,从而可以实现跨域通信。这里需要注意的是document.domain的设置必须与域名的主域名一致,否则document.domain的设置是非法的。如document.domain=‘Alibaba.com’,这肯定是不合法的,无法实现跨域通信。
2-6 location.hash+iframe
location.hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。例如当前的 URL 是 http://fe.xiaojukeji.com:1234/test.htm#part2,则location.hash的值为part2。
三个页面之间传递参数用的是location.hash,改变hash并不会导致页面刷新。本文参考链接13设计实验,检查location.hash的跨域效果。
主服务器
locationHash.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>location.hash实现跨域</title>
<script type="text/javascript">
//通过动态创建iframe的hash发送请求
function sendRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
//跨域发送请求给html, 参数是sayHello
ifr.src = 'http://fe_vm.xiaojukeji.com/hash/hash.html#sayHello';
document.body.appendChild(ifr);
}
//获取返回值的方法
function checkHash() {
var data = location.hash ?
location.hash.substring(1) : '';
if (data) {
//处理返回值
alert(data);
location.hash='';
}
}
//定时检查自己的hash值
setInterval(checkHash, 2000);
window.onload = sendRequest;
</script>
</head>
<body>
</body>
</html>
loctionHash2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>locations hash实现跨域</title>
<script type="text/javascript">
//location2 和 location2s属于同一个域,
// 可通过parent.parent获取window对象
parent.parent.location.hash =
self.location.hash.substring(1);
</script>
</head>
<body>
</body>
</html>
从服务器代码
hash.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>domain实现跨域</title>
<script type="text/javascript">
function checkHash(){
var data = '';
//模拟一个简单的参数处理操作
switch(location.hash){
case '#sayHello': data = 'hello world!';break;
default: break;
}
data && callBack('#'+data);
}
function callBack(hash){
// ie、chrome的安全机制无法修改parent.location.hash,
// 所以要利用一个中间的fe.xiaojukeji.com域下的代理iframe
var proxy = document.createElement('iframe');
proxy.style.display = 'none';
proxy.src = 'http://fe.xiaojukeji.com/HASH/locationHash2.html'+hash;
document.body.appendChild(proxy);
}
window.onload = checkHash;
</script>
</head>
<body>
</body>
</html>
运行结果截图
页面通信示意图
结合页面通信示意图,我们可以得到使用location.hash进行跨域通信的过程如下:
(1)主页面locationHash(外层棕黄色部分),首选创建iframe,并设置src=“http://fe_vm.xiaojukeji.com/hash/hash.html#sayHe
llo”,设置定时检查locationHash主页面的hash值。
(2)hash.html(绿色部分)获取自身页面的hash值,根据主页面传递的hash返回相应的结果(具体可参见代码)。在数据转换完成后,创建新的if
rame,设置src=http://fe.xiaojukeji.com/HASH/locationHash2.html'+hash。iframe与主页面locationHash是同一域名下。
(3)代理页面(内层棕黄色部分),将自身hash赋值给主页面locationHash的hash,完成信息的传递。parent.parent.location.hash 等同
于 locationHash.hash,self.location.hash等同于代理页面的hash值。
(4)主页面定时检查,检查得到hash的变化,输出变化值,从而完成一次跨域的信息传递。
3 参考文献
[1]同源策略
[2]wiki-同源策略
[3]Cross-origin resource sharing
[4]Cross-origin resource sharing.
[5]跨域共享学习笔记
[6]跨域资源共享CORS详解
[7]CORS协议
[8]JSONP协议
[9]JSONP详解
[10]window.name跨域
[11]HTML5 postMessage 和 onmessage API 详细应用
[12]location.hash
[13]location.hash+iframe跨域
[14]webSocket 跨域
来源:CSDN
作者:浪子闲人-ljc
链接:https://blog.csdn.net/qq401767529/article/details/52298285