同源策略限制一個源加載的文檔或文檔與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的安全機制。
什麼是同源呢? 若是協議,端口(若是指定了一個)和域名對於兩個頁面是相同的,則兩個頁面具備相同的源。
下表給出了相對http://store.company.com/dir/...同源檢測的示例:html
跨域網絡訪問一般分爲3種ajax
一般容許進行跨域寫操做(Cross-origin writes)。例如連接(links),重定向以及表單提交。特定少數的HTTP請求須要添加 preflight。json
一般容許跨域資源嵌入(Cross-origin embedding)。跨域
一般不容許跨域讀操做(Cross-origin reads)。但常能夠經過內嵌資源來巧妙的進行讀取訪問。例如能夠讀取嵌入圖片的高度和寬度,調用內嵌腳本的方法。
另外,同源策略約束了XMLHttpRequest
,也就是說ajax進行跨域訪問會報錯。瀏覽器
原理: 再瀏覽器中打開一個頁面中,或用iframe打開一個頁面時會建立一個window對象,當頁面加載一個新的頁面時,window.name屬性是不會變的,所以咱們能夠在頁面中動態建立一個iframe頁面指向另外一個域,將數據賦值個window.name屬性。(值得注意的是,此時咱們沒法直接訪問window.name),咱們還須要將將iframe的src指向相同域的空白頁面。以後再將iframe刪除就能夠了安全
//http://localhost:3000/request.js function CreateIframe(src, nextsrc){ var iframe = document.createElement('iframe'); var flag = true; iframe.src = src; iframe.style.display = 'none'; iframe.onload = function(){ if(flag){ iframe.src = nextsrc; flag = false; }else{ p.innerHTML = iframe.contentWindow.name; iframe.contentWindow.close(); document.body.removeChild(iframe); iframe.src = ''; iframe = null }; }; document.body.appendChild(iframe); } CreateIframe('http://localhost:3001/a.html', 'http://localhost:3000/b.html');
//http://localhost:3001/response.js function ajax(url, method){ const xhr = new XMLHttpRequest(); xhr.onload = function(data){ window.name = this.responseText console.log(window.name); } xhr.open(method, url, true); xhr.send(null); } ajax('http://localhost:3001/req', 'GET');
原理:經過該document.domain來設置域名,可是有侷限性,也就是一級域名一致才能夠。服務器
//http://localhost:3000/request.js document.domain = 'http://localhost:3001'; document.getElementById('iframe').onload = function(){ var win = iframe.contentWindow; var doc = win.document; console.log(win.data); }
//http://localhost:3001/response.js document.domain = 'http://localhost:3001'; var data = '123';
原理: JSONP實現跨域請求的原理簡單的說,就是動態建立<script>標籤,而後利用<script>的src 不受同源策略約束來跨域獲取數據。網絡
//index.html <script src="./jsonp.js"></script> <script> function myFunction (data) { console.log(data.message); } Jsonp('http://localhost:3001', 'myFunction'); </script>
//jsonp.js const Jsonp = (() => { function jsonp(url, handle){ let script = document.createElement('script'); script.setAttribute('src', `${url}?callback=${handle}`); document.body.appendChild(script); } return jsonp; })()
//server.js app.get('/', function (req, res) { var callbackName = req.query.callback; // myFunction res.send(callbackName+"({'message': 'It is JSONP!'});"); })
PostMessage是HTML5的API,postMessage() 方法被調用時,會在全部頁面腳本執行完畢以後向目標窗口派發一個 MessageEvent 消息。 該MessageEvent消息有四個屬性須要注意: message 屬性表示該message 的類型; data 屬性爲 window.postMessage 的第一個參數;origin 屬性表示調用window.postMessage() 方法時調用頁面的當前狀態; source 屬性記錄調用 window.postMessage() 方法的窗口信息。
只有經過其餘窗口的一個引用,好比iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames。才能使用app
////http://localhost:3000/request.js var popup =window.open('http://localhost:3001/index4.html'); function receive(event){ if(event.origin !== 'http://localhost:3001') return; document.querySelector('#message').innerHTML = event.data; } window.addEventListener('message', receive, false);
//http://localhost:3001/response.js var popup = window.opener; popup.postMessage('發送消息', 'http://localhost:3000/'); window.addEventListener('message', (e) => { if(e.origin !== 'http://localhost:3001') return; document.querySelector('#message').innerHTML = e.data; //e.source.postMessage('發送消息', e.origin); }, false)
cors主要靠服務器,只要服務器實現了cors接口,就能夠跨源通訊。具體的原理能夠看阮老師的文章跨域資源共享 CORS 詳解cors