雜談:前端Web通訊

前端Web通訊

Web2.0以來,Ajax的出世,解決了傳統表單提交頁面跳轉,閃爍白屏等問題。使得Web頁面能夠實現局部更新,不只減小了網絡帶寬,還大大提高了用戶體驗。html

但Ajax並不是是一把萬能的鑰匙,足以打開Web通訊這扇大門,當請求遇到跨域通訊時,Ajax就沒轍了。前端

Web的快速發展讓開發走向工程化的同時,要求工做維度進行劃分(前端後端分工明細),以便擴展維護日益複雜龐大的項目需求。而先後端分離的開發方式正是這種需求背景下衍生的產物。(之前混編的代碼如今是不再想看到)html5

先後端分離的開發方式,如何進行數據通訊是開發人員繞不過去的問題。做爲開發同窗的小夥伴客戶端的瀏覽器,有點小調皮還作了一個同源策略的限制,當咱們的數據請求遇到不一樣源的狀況下(跨域),咱們就得嘗試其它的通訊方法,不能Ajax一條道走到黑。web

什麼是同源策略及限制

同源策略限制從一個源加載的文檔或腳本如何與來自另外一個源的資源進行交互。這是一個用於隔離潛在惡意文件的關鍵的安全機制。

同源要求協議,域名,端口(默認80)三者都相同,不然爲非同源。json

同源策略限制:

  • Cookie, LocalStorage和IndexDB沒法讀取
  • Dom沒法獲取
  • Ajax請求不能發送

先後端如何通訊

  1. Ajax(僅支持同源)
  2. WebSocket (不受同源限制)
  3. CORS (都支持,新的W3C通訊標準)

如何建立Ajax

  • XMLHttpRequest對象的工做流程
  • 兼容性處理
  • 事件的觸發條件
  • 事件的觸發順序
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的鑰匙,來從新配鑰匙開鎖後端

跨域通訊的幾種方式

  1. JSONP
  2. Hash
  3. postMessage (HTML5)
  4. WebSocket
  5. CORS (新的W3C通訊標準)

1. JSONP

JSONP原理:客戶端經過動態建立script標籤異步加載來實現,服務端callback返回客戶端定義的方法名,讓客戶端進行調用獲取數據。跨域

只支持Get請求 (GET與POST的區別這裏暫不細講)瀏覽器

// 客戶端發送請求
<script src="http://www.abc.com?data=name&callback=jsonpname"></script>
<script>
jsonpname({
    data: {
        ...
    }
})
</script>

2. Hash

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;
}

3. postMessage

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)

項目中應用場景:

  1. 頁面和其打開的新窗口的數據傳遞
  2. 多窗口之間消息傳遞
  3. 頁面與嵌套的iframe消息傳遞
  4. 上面三個問題的跨域數據傳遞

4. WebSocket

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.');
}

5. CORS

CORS是一個W3C標準,全稱是"跨域資源共享"(Cross-origin resource sharing)。它容許瀏覽器向跨源服務器,發出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制。

瀏覽器兼容在XHR(IE8/9)及XHR2(>=IE10)下須要作兼容處理。

// CORS代碼示例
fetch('/url', {
    method: 'get',
}).then(function(res){
    ...
}).catch(function(err) {
    // 錯誤
})

-- End --

JSONP有更好的兼容性,能兼容低版本瀏覽器,可是基於Get傳輸數據,會由於瀏覽器Url長度限制而限制數據大小。CORS在不考慮低版本瀏覽器時,無疑是目前最好先後端通訊方案(單向),雙向選擇WebSocket,而多個頁面之間的數據通訊,如內嵌iFrame等,則推薦postMessage。

每種方案有不一樣的應用場景,解決問題不僅有一種解決方案,實際項目開發中,需根據實際需求來挑選最優的方案。


參考資料

  1. html5 postMessage解決跨域、跨窗口消息傳遞
  2. 乾貨 | 前端經常使用的通訊技術
  3. 阮一峯 — 跨域資源共享 CORS 詳解
  4. CORS正確使用姿式
做者:以樂之名 本文原創,有不當的地方歡迎指出。轉載請指明出處。
相關文章
相關標籤/搜索