一、同源和跨域
首先介紹一下同源策略,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