页面之间的通信
一、同源和跨域
首先介绍一下同源策略,URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。同源策略限制了从一个源加载的文档或脚本与来自另一个源的资源进行交互,这是一个用于隔离潜在恶意软件的关键安全机制。
跨域是指从一个域名去请求另一个域名的资源,严格来说,只要协议、域名、端口、任何一个不同,就会被当做跨域。而<img/>和<script></script>两个标签不受同源策略影响。可以从其他域获取资源。
二、同源通信
1、BroadCast Channel
BroadCast Channel 创建一个所有同源页面都可以共享的(广播)频道。当所有页面都监听同一频道的消息时,其中某一个页面通过它发送的消息就会被其他所有页面收到。
父页面:
<script> let cast = new BroadcastChannel("channel1"); myObj = {from: "children1", content: "add" }; cast.postMessage(myObj); document.write("hello"); </script> <iframe name="myFrame" src="child.html"></iframe>
子页面child.html:
<script> let cast1 = new BroadcastChannel("channel1"); cast1.onmessage = function (e){ var text = e.data; var text1 = text.content +""+text.from; console.log(text1); } </script>
打开父页面和子页面,在子页面的控制台可以看到:
2、LocalStorage
LocalStorage是持久保存在客户端的存储对象,而LocalStorage在变化时会触发storage事件,因此可以将消息保存在localstorage,然后监听storage事件来获取消息。
页面A:
<button>click</button> <script> document.querySelector('button').onclick = function () { localStorage.setItem('Num', Math.random()*10); document.write("hello1"); } </script>
页面B:
<script> document.write("hello3"); window.addEventListener('storage', function (e) { document.write("hello"); console.log(e.key) document.write(e.key); console.log(e.newValue) document.write(e.newValue); }); </script>
非常坑的是,这种方式改变localstorage只能通过域名访问才可以生效,在本地浏览器通过file//的方式监听不到事件。以下是在域名下的网址访问显示出来的结果。
3、ajax
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。他是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
ajax的流程:
1. 创建一个对象 XMLHttpRequest
2.监听请求成功后的状态变化
3.设置请求参数
4.发起请求
5.操作DOM,实现动态局部刷新
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script> function loadXMLDoc() { var xmlhttp; if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码 xmlhttp=new XMLHttpRequest(); } else { // IE6, IE5 浏览器执行代码 xmlhttp=new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { document.getElementById("myDiv").innerHTML=xmlhttp.responseText; } } xmlhttp.open("GET","1.txt",true); xmlhttp.send(); } window.onload=function(){ var obt=document.getElementById("bt"); obt.onclick=function(){ loadXMLDoc(); } } </script> </head> <body> <div id="myDiv"><h2>使用 AJAX 修改该文本内容</h2></div> <button id="bt">修改内容</button> </body> </html>
这里又坑了一把,xmlhttp.status==0是在本地运行的,然而在本地运行是获取不到xmlhttp.responseText的值的,读取出来一直是空。所以没有办法只能将代码放到远程服务器上面运行,并且xmlhttp.status==200。
点击按钮:文中字符串是修改之后的字符串。
当然同源的方法并不一定只有这些,这里只介绍这些,接下来看看跨域通信。
三、跨域通信
1、JSONP
JSONP的基本思想:网页通过添加一个<script>
元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。它有个限制,只能用GET请求,并且要求返回JavaScript。这种方式跨域实际上是利用了浏览器允许跨域引用JavaScript资源。
前端html页面:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JSONP 实例</title> </head> <body> <div id="divCustomers"></div> <script type="text/javascript"> function callbackFunction(result, methodName) { var html = '<ul>'; for(var i = 0; i < result.length; i++) { html += '<li>' + result[i] + '</li>'; } html += '</ul>'; document.getElementById('divCustomers').innerHTML = html; } </script> <script type="text/javascript" src="http://www.runoob.com/try/ajax/jsonp.php?jsoncallback=callbackFunction"></script> </body> </html>
后台php页面:
<?php header('Content-type: application/json'); //获取回调函数名 $jsoncallback = htmlspecialchars($_REQUEST ['jsoncallback']); //json数据 $json_data = '["customername1","customername2"]'; //输出jsonp格式的数据 echo $jsoncallback . "(" . $json_data . ")"; ?>
这个是菜鸟教程JSONP的一个实例,假设客户期望返回JSON数据:["customername1","customername2"]。
真正返回到客户端的数据显示为: callbackFunction(["customername1","customername2"])。
2、hash
hash的值是在页面中的定位,#代表网页中的一个位置,其右边的字符,就是hash的标识符。
通过改变url的hash值,然后在要交流的页面监听事件,只要监听到hash的值变化,就执行代码。
如:场景:页面A通过iframe或frame嵌入了跨域的页面B,现在A给B发消息,怎么操作?
A页面中:
B页面中:
window.onhashchange = function(){
var data = window.location.hash; //通过onhashchange方法见监听,url中的hash是否发生变化
}
3、postMessage
A页面直接调用postMessage函数给B页面发送消息,B页面通过监听message来接收。
window.postMessage() 方法被调用时,会在所有页面脚本执行完毕之后向目标窗口派发一个 MessageEvent
消息。 该MessageEvent
消息有四个属性需要注意: message 属性表示该message 的类型; data 属性为 window.postMessage 的第一个参数;origin 属性表示调用window.postMessage() 方法时调用页面的当前状态; source 属性记录调用 window.postMessage() 方法的窗口信息。
A页面:
4、websocket
WebSocket 是一种通信协议,使用ws://
(非加密)和wss://
(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
<script type="text/javascript">
function WebSocketTest()
{
if ("WebSocket" in window)
{
alert("您的浏览器支持 WebSocket!");
// 打开一个 web socket
var ws = new WebSocket("ws://localhost:9998/echo");
ws.onopen = function()
{
// Web Socket 已连接上,使用 send() 方法发送数据
ws.send("发送数据");
alert("数据发送中...");
};
ws.onmessage = function (evt)
{
var received_msg = evt.data;
alert("数据已接收...");
};
ws.onclose = function()
{
// 关闭 websocket
alert("连接已关闭...");
};
}
else
{
// 浏览器不支持 WebSocket
alert("您的浏览器不支持 WebSocket!");
}
}
</script>
</head>
<body>
<div id="sse">
<a href="javascript:WebSocketTest()">运行 WebSocket</a>
</div>
</body>
</html>
5、cros
CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源。它允许浏览器向跨源服务器,发出XMLHttpRequest
请求,从而克服了AJAX只能同源使用的限制。
详情参考:http://www.ruanyifeng.com/blog/2016/04/cors.html
本文参考:
https://segmentfault.com/a/1190000009624849
https://www.jianshu.com/p/0f4ecf92504c
https://www.jianshu.com/p/cd89ccb7e8fd