Web2.0以來,Ajax的出世,解決了傳統表單提交頁面跳轉,閃爍白屏等問題。使得Web頁面能夠實現局部更新,不只減小了網絡帶寬,還大大提高了用戶體驗。html
但Ajax並不是是一把萬能的鑰匙,足以打開Web通訊這扇大門,當請求遇到跨域通訊時,Ajax就沒轍了。前端
Web的快速發展讓開發走向工程化的同時,要求工做維度進行劃分(前端後端分工明細),以便擴展維護日益複雜龐大的項目需求。而先後端分離的開發方式正是這種需求背景下衍生的產物。(之前混編的代碼如今是不再想看到)html5
先後端分離的開發方式,如何進行數據通訊是開發人員繞不過去的問題。做爲開發同窗的小夥伴客戶端的瀏覽器,有點小調皮還作了一個同源策略的限制,當咱們的數據請求遇到不一樣源的狀況下(跨域),咱們就得嘗試其它的通訊方法,不能Ajax一條道走到黑。web
同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。
同源要求協議,域名,端口(默認80)三者都相同,不然爲非同源。json
var xhr = XMLHttpRequest ? new XMLHttpRequest() : new window.ActiveXObject('Microsoft') 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); xhr.send(); } if (type === 'POST') { xhr.open(type, url, true); xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); xhr.send(data.join('&')); } xhr.onload = function() { if (xhr.status === 200 || xhr.status === 304) { var res; if (opt.success && opt.success instanceof Function) { res = xhr.responseText; if (typeof res === 'string') { res = JSON.parse(res); opt.success.call(xhr, res) } } else { if (opt.error && opt.error instanceof Function) { opt.error.call(xhr, res); } } } }
同源下,咱們能夠直接使用Ajax來與後端同窗作數據通訊,可是遇到跨域請求時,咱們就得更換手中這把Ajax的鑰匙,來從新配鑰匙開鎖後端
JSONP原理:客戶端經過動態建立script標籤異步加載來實現,服務端callback返回客戶端定義的方法名,讓客戶端進行調用獲取數據。跨域
只支持Get請求 (GET與POST的區別這裏暫不細講)瀏覽器
// 客戶端發送請求 <script src="http://www.abc.com?data=name&callback=jsonpname"></script> <script> jsonpname({ data: { ... } }) </script>
Hash原理:經過window.onhashchange
事件監聽來獲取url中hash值來實現數據傳輸。與Get同樣,有Url長度限制安全
// A中代碼 var B = document.getElementdByTagName('iframe'); B.src = B.src + '#' + 'data'; // B中代碼 window.onhashchange = function(){ var data = window.location.hash; }
postMessage是HTML5的API,可參考開發文檔window.postMessage服務器
// A.com向B.com發送信息 Bwindow.postMessage('data','http://B.com') // B中監聽 window.addEventListener('message', function(event){ console.log(event.origin); // http://A.com console.log(event.source); // Bwindow console.log(event.data); // data }, false)
項目中應用場景:
WebSocket是HTML5開始提供的一種在單個 TCP 鏈接上進行全雙工通信的協議,自己不受同源限制。
// WebSocket代碼示例 var ws = new WebSocket('wss://echo.websocket.org'); ws.onopen = function (evt) { console.log('Connection open ...'); ws.send('Hello WebSocket!'); }; ws.onmessage = function (evt) { console.log('Received Message: ' + evt.data); ws.close(); } ws.onclose = function (evt) { console.log('Connection closed.'); }
CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。
瀏覽器兼容在XHR(IE8/9)及XHR2(>=IE10)下須要作兼容處理。
// CORS代碼示例 fetch('/url', { method: 'get', }).then(function(res){ ... }).catch(function(err) { // 錯誤 })
JSONP有更好的兼容性,能兼容低版本瀏覽器,可是基於Get傳輸數據,會由於瀏覽器Url長度限制而限制數據大小。CORS在不考慮低版本瀏覽器時,無疑是目前最好先後端通訊方案(單向),雙向選擇WebSocket,而多個頁面之間的數據通訊,如內嵌iFrame等,則推薦postMessage。
每種方案有不一樣的應用場景,解決問題不僅有一種解決方案,實際項目開發中,需根據實際需求來挑選最優的方案。
參考資料
做者:以樂之名 本文原創,有不當的地方歡迎指出。轉載請指明出處。