源:協議(http://)、域名(www.example.com)、端口(80)javascript
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。html
目的:這是一個用於隔離潛在惡意文件的關鍵的安全機制。java
限制範圍:web
參考文檔:瀏覽器同源政策及其規避方法ajax
能夠跨域的三個標籤:json
三個標籤的場景segmentfault
var xhr = XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
readyState後端
statusapi
var xhr = new XMLHttpRequest(); xhr.open("GET","/api",false); xhr.onreadystatechange = function(){ //這裏的函數異步執行 if(xhr.readyState == 4){ if(xhr.status == 200){ alert(xhr.responseText); } } } xhr.send(null);
參考文檔:聊聊Ajax那些事跨域
util.json = function (options) { var opt = { url: '', type: 'get', data: {}, success: function () {}, error: function () {}, }; util.extend(opt, options); if (opt.url) { var xhr = XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');//1.聲明對象,處理IE兼容性 var data = opt.data, url = opt.url, type = opt.type.toUpperCase(), dataArr = []; for (var k in data) { dataArr.push(k + '=' + data[k]); } if (type === 'GET') { url = url + '?' + dataArr.join('&'); xhr.open(type, url.replace(/\?$/g, ''), true);//2.open,肯定XMLHttpRequest對象的發送方式(用的那個協議:GET/POST等) xhr.send();//3.發送請求 } if (type === 'POST') { xhr.open(type, url, true); xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(dataArr.join('&')); } xhr.onload = function () {//4.響應 if (xhr.status === 200 || xhr.status === 304 ||xhr.status === 206) {//206適用於接收部分媒體資源,304利用本地緩存 var res; if (opt.success && opt.success instanceof Function) { res = xhr.responseText; if (typeof res ==== 'string') { res = JSON.parse(res);//轉成JSON opt.success.call(xhr, res); } } } else { if (opt.error && opt.error instanceof Function) { opt.error.call(xhr, res); } } }; } };
<script> //此處定義回調函數 window.callback = function(data){ //這是咱們跨域獲得的信息 console.log(data); } </script> <script src="http://www.baidu.com/api.js"></script> <!-- 以上將返回 callback({x:100,y:200}),此處執行回調函數 -->
原理:經過script標籤的異步加載實現的;
//JSONP //1.瀏覽器發送請求,告訴服務端callback的名稱 <script src="http://www.abc.com/?data=name&callback=jsonp" charset="utf-8"></script> //2.服務器響應下發script內容,callback的名稱做爲函數名返回 <script> jsonp({ data:{ } }) </script> //代碼實現 /** * [function 在頁面中注入js腳本] */ util.createScript = function (url, charset) { var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); charset && script.setAttribute('charset', charset); script.setAttribute('src', url); script.async = true; return script; }; //本地須要有以callback的名稱建立函數 util.jsonp = function (url, onsuccess, onerror, charset) { var callbackName = util.getName('tt_player'); window[callbackName] = function () { if (onsuccess && util.isFunction(onsuccess)) { onsuccess(arguments[0]); } }; var script = util.createScript(url + '&callback=' + callbackName, charset); script.onload = script.onreadystatechange = function () { if (!script.readyState || /loaded|complete/.test(script.readyState)) { script.onload = script.onreadystatechange = null; // 移除該script的 DOM 對象 if (script.parentNode) { script.parentNode.removeChild(script); } // 刪除函數或變量 window[callbackName] = null; } }; script.onerror = function () { if (onerror && util.isFunction(onerror)) { onerror(); } }; document.getElementsByTagName('head')[0].appendChild(script); };
url地址中#後邊的叫Hash,Hash變更頁面不會刷新(Hash作跨域通訊的基本原理);
url地址中?後邊的叫search,search變更頁面會刷新頁面,因此search不能作跨域通訊。
// hash // 場景:當前頁面 A 經過iframe或frame嵌入了跨域的頁面 B,要給跨域的 B 發送消息 // 在A中僞代碼以下: var B = document.getElementsByTagName('iframe'); B.src = B.src + '#' + 'data';//經過JSON.stringify()轉成字符串'data' // 在B中的僞代碼以下 window.onhashchange = function () { var data = window.location.hash; };
H5中新增長的實現跨域通訊的方式
// postMessage // 場景:窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息 Bwindow.postMessage('data', 'http://B.com'); // 在窗口B中監聽 Awindow.addEventListener('message', function (event) { console.log(event.origin);//http://A.com console.log(event.source);//Awindow console.log(event.data);//data }, false);
// Websocket var ws = new WebSocket('wss://echo.websocket.org');//ws非加密,wss加密 //發送消息onopen ws.onopen = function (evt) { console.log('Connection open ...'); ws.send('Hello WebSockets!'); }; //接收消息onmessage ws.onmessage = function (evt) { console.log('Received Message: ', evt.data); ws.close(); }; //關閉鏈接 ws.onclose = function (evt) { console.log('Connection closed.'); };
參考文檔:WebSocket 教程
新的通訊標準(經過新的API:fetch()實現CORS通訊)。能夠理解爲:支持跨域通訊的Ajax。當你在瀏覽器中發送一個ajax跨域請求時,瀏覽器會在http頭中加入一個origin。若是隻是一個普通的ajax,跨域時就會被瀏覽器攔截。
// CORS // url(必選),options(可選) fetch('/some/url/', { method: 'get', }).then(function (response) { //then 回調 }).catch(function (err) { // catch捕獲錯誤;出錯了,等價於 then 的第二個參數,但這樣更好用更直觀 });
參考文檔:跨域資源共享 CORS 詳解
//注意:不一樣後端語言的寫法可能不同 //第二個參數填寫容許跨域的域名城,不建議直接寫"*" response.setHeader("Access-Control-Allow-Origin","http://a.com,http://b.com"); response.setHeader("Access-Control-Allow-Headers", "X-Requested-With"); response.addHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS"); //接受跨域的cookie response.setHeader("Access-Control-Allow-Credentials", "true");