摘要:接口用于接收服務(wù)器發(fā)送的事件。因此,是目前來(lái)說(shuō)最佳的選擇。最大特點(diǎn)就是,服務(wù)器可以主動(dòng)向客戶(hù)端推送消息,客戶(hù)端也可以主動(dòng)向服務(wù)器發(fā)送信息,是一種不受限的全雙工通信。若是,則交給的回調(diào)函數(shù)處理,否則,還是走正常的回調(diào)的路子。
使用 WebSocket 的理由
傳統(tǒng)的http協(xié)議有一個(gè)根本性的缺陷,那就是請(qǐng)求只能由客戶(hù)端向服務(wù)器發(fā)起,服務(wù)器接收到請(qǐng)求后再進(jìn)行響應(yīng),把數(shù)據(jù)返回給客戶(hù)端。也就是說(shuō),服務(wù)器是沒(méi)有辦法主動(dòng)向客戶(hù)端傳送消息的。
這樣一來(lái),如果服務(wù)器有狀態(tài)是頻繁變化的,那么,客戶(hù)端想要實(shí)時(shí)獲悉這些狀態(tài)勢(shì)必非常麻煩。如在線多人游戲,聊天室等。
一種可行的解決方案是使用輪詢(xún)。輪詢(xún)是指瀏覽器通過(guò)JavaScript啟動(dòng)一個(gè)定時(shí)器,然后以固定的間隔給服務(wù)器發(fā)請(qǐng)求,詢(xún)問(wèn)服務(wù)器有沒(méi)有新消息。
這種機(jī)制不僅效率低下,實(shí)時(shí)性不夠,而且頻繁地發(fā)起請(qǐng)求也會(huì)給服務(wù)器帶來(lái)極大的壓力。
另外一種比較靠譜的技術(shù)是HTML5的EventSource。EventSource 接口用于接收服務(wù)器發(fā)送的事件。它通過(guò)HTTP連接到一個(gè)服務(wù)器,以text/event-stream 格式接收事件, 不關(guān)閉連接。
相對(duì)于WebSocket,這種技術(shù)要簡(jiǎn)單很多,但是其只是從服務(wù)器端往客戶(hù)端單向傳輸數(shù)據(jù),并不能實(shí)現(xiàn)真正意義上的全雙工通信。因此,WebSocket是目前來(lái)說(shuō)最佳的選擇。
有興趣了解EventSource的小伙伴可以點(diǎn)擊這里
WebSocket 協(xié)議WebSocket是HTML5新增的協(xié)議,其誕生于2008年。最大特點(diǎn)就是,服務(wù)器可以主動(dòng)向客戶(hù)端推送消息,客戶(hù)端也可以主動(dòng)向服務(wù)器發(fā)送信息,是一種不受限的全雙工通信。
該協(xié)議有以下特征:
握手階段利用了HTTP協(xié)議來(lái)建立連接,因此WebSocket連接必須由瀏覽器發(fā)起。
建立在 TCP 協(xié)議之上,服務(wù)器端的實(shí)現(xiàn)比較容易。
其可以接收和發(fā)送的數(shù)據(jù)有兩種,一種是文本,一種是二進(jìn)制數(shù)據(jù)(blob對(duì)象或Arraybuffer對(duì)象)。一般情況下,我們可以發(fā)送JSON格式的文本,這樣,在瀏覽器處理起來(lái)就十分容易。
數(shù)據(jù)格式比較輕量,性能開(kāi)銷(xiāo)小,通信高效。
請(qǐng)求是以ws://為開(kāi)頭的地址(如果加密,則為wss://)。
WebSocket協(xié)議本身不要求同源策略,也就是某個(gè)地址為"http://a.com"的網(wǎng)頁(yè)可以通過(guò)WebSocket連接到"ws://b.com"。但是,瀏覽器會(huì)發(fā)送Origin的HTTP頭給服務(wù)器,服務(wù)器可以根據(jù)Origin拒絕這個(gè)WebSocket請(qǐng)求。
瀏覽器支持情況Chrome
Firefox
IE >= 10
Sarafi >= 6
Android >= 4.4
iOS >= 8
服務(wù)端實(shí)現(xiàn)不同的編程語(yǔ)言和框架,實(shí)現(xiàn)方式各有不同。這里主要講一下用node如何實(shí)現(xiàn)。
node常用的實(shí)現(xiàn)有一下幾種:
Socket.IO
WebSocket-Node
μWebSockets
具體如何使用可以查看它們各自的api。下面,我要詳細(xì)介紹的是另一個(gè)WebSocket模塊ws。
通過(guò)npm install ws --save之后,我們就可以可以編寫(xiě)一個(gè)簡(jiǎn)單WebSocket服務(wù)器程序。
// 首先導(dǎo)入ws模塊 let WebSocket = require("ws"); // 通過(guò)ws模塊的Server類(lèi)實(shí)例化一個(gè)websocket服務(wù)器 let webSocketServer = new WebSocket.Server({ port: 8030 }, err => { console.log("The WebSocket Server already running on: 8030"); }); // 監(jiān)聽(tīng)客戶(hù)端請(qǐng)求接入的connection事件,連接建立后,回調(diào)函數(shù)中會(huì)傳入這個(gè)WebSocket連接實(shí)例 webSocketServer.on("connection", ws => { console.log(`Server is connected`) // 對(duì)于每個(gè)WebSocket連接,可以綁定監(jiān)聽(tīng)某些事件來(lái)進(jìn)行不同的處理。這里,通過(guò)響應(yīng)message事件,在收到客戶(hù)端發(fā)來(lái)消息后再返回一個(gè)消息過(guò)去。 ws.on("message", mes => { console.log(`Message sent by client: ${mes}`); ws.send(`data responded by Server: ${mes}`, err => { if (err) { console.log(`Server error: ${err}`); } }) }) })
也可以對(duì)http服務(wù)器進(jìn)行拓展,在其基礎(chǔ)上建立WebSocket服務(wù)器。
const Koa = require("koa"); const WebSocket = require("ws"); const bodyParser = require("koa-bodyparser"); const controller = require("./controller.js"); const server = new Koa(); const webSocketServer = new WebSocket.Server({server}, () => console.log("The WebSocket Server already running on: 8030")); // 為websocket服務(wù)器添加一個(gè)broadcast()方法 webSocketServer.broadcast = data => { // 通過(guò)遍歷webSocketServer.clients,找到所有與該服務(wù)器成功建立websocket連接的客戶(hù)端,發(fā)送同一條消息 for (const client of webSocketServer.clients) { if (client.readyState === WebSocket.OPEN) { client.send(data, err => console.log(`Server error: ${err}`)); } } } webSocketServer.on("connection", ws => { console.log(`Server is connected`); ws.on("message", mes => { console.log(`Message sent by client: ${mes}`); // 接受到其中一個(gè)客戶(hù)端發(fā)來(lái)的消息后,廣播給所有同時(shí)連接過(guò)來(lái)的客戶(hù)端 const data = { message: mes } webSocketServer.broadcast(JSON.stringify(data)) }) }) server.use(bodyParser()); server.use(controller()); server.listen(8030); console.log("server running on 8030...");
現(xiàn)在,websocket服務(wù)器與http服務(wù)器同時(shí)使用8030端口。當(dāng)有一個(gè)請(qǐng)求發(fā)送過(guò)來(lái),首先會(huì)判斷其是否ws請(qǐng)求。若是,則交給WebSocketServer的回調(diào)函數(shù)處理,否則,還是走正常的http server回調(diào)的路子。
另外,我們注意到,這里還給WebSocketServer添加了一個(gè)broadcast()方法,用于將消息廣播到所有與該服務(wù)器成功建立WebSocket連接的客戶(hù)端上。
每當(dāng)從其中一個(gè)客戶(hù)端收到一條消息,就將該消息發(fā)送到所有WebSocket連接上,基于這種方式,我們就可以搭建一個(gè)聊天室應(yīng)用的后臺(tái)服務(wù)。
ws模塊的完整使用方法請(qǐng)看這里
客戶(hù)端實(shí)現(xiàn)客戶(hù)端要?jiǎng)?chuàng)建一個(gè)WebSocket連接就比較簡(jiǎn)單了。下面是一個(gè)簡(jiǎn)單的事例:
// 創(chuàng)建一個(gè)WebSocket連接: var ws = new WebSocket("ws://localhost:8030/ws"); ws.onopen = function(event) { console.log("Connection open"); // 給服務(wù)器發(fā)送一個(gè)消息: ws.send("Hello WebSocket!"); }; // 響應(yīng)onmessage事件: ws.onmessage = function(event) { console.log(event.data); }; // 也可以指定接收的二進(jìn)制數(shù)據(jù)類(lèi)型為blob對(duì)象 ws.binaryType = "blob"; ws.onmessage = function(event) { console.log(event.data.size); }; // 或 // 指定接收的二進(jìn)制數(shù)據(jù)類(lèi)型為ArrayBuffer對(duì)象 ws.binaryType = "arraybuffer"; ws.onmessage = function(event) { console.log(event.data.byteLength); };
詳細(xì)的屬性和方法可以看這里
另外,使用ws模塊提供的WebSocket構(gòu)造函數(shù)也可以充當(dāng)客戶(hù)端創(chuàng)建連接。
let ws = new WebSocket("ws://localhost:8030/ws"); // 打開(kāi)WebSocket連接后立刻發(fā)送一條消息 ws.on("open", () => { console.log(`Client open`); ws.send("Hello WebSocket!"); }); // 響應(yīng)收到的消息 ws.on("message", mes => { console.log(mes); });參考鏈接
http://www.ruanyifeng.com/blo...
https://www.liaoxuefeng.com/w...
http://es6.ruanyifeng.com/#do...
https://developer.mozilla.org...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/99736.html
摘要:一什么是跨域跨域簡(jiǎn)單的理解就是同源策略的限制。同源策略限制的內(nèi)容請(qǐng)求不能正常進(jìn)行。同源策略默認(rèn)地址是網(wǎng)頁(yè)的本身。 一、什么是跨域? 跨域簡(jiǎn)單的理解就是JavaScript同源策略的限制。是出于安全的考慮,a.com域名下的js不能操作b.com或者c.com域名下的對(duì)象。 當(dāng)協(xié)議、子域名、主域名、端口號(hào)中任意一個(gè)不相同時(shí),都算作不同域。不同域之間相互請(qǐng)求資源,就算叫跨域。 一個(gè)正常...
摘要:關(guān)于模塊化的一點(diǎn)想法對(duì)于模塊化,我還是想說(shuō)明一下,模塊化重要的是思想,而不是實(shí)現(xiàn)。而且這樣的模塊,復(fù)用基本是零。 沒(méi)有模塊化之前,我們是怎么開(kāi)發(fā)的 剛剛從業(yè)那會(huì),公司是沒(méi)用模塊化的,那代碼是怎么組織的呢?首先有一個(gè)common.js,這里面放的是一些公用的東西,比如:用戶(hù)的登錄注冊(cè)、工具類(lèi)、經(jīng)常用到的全局變量、還有一些常用的函數(shù);還有一個(gè)head.js,這里面放的是一些網(wǎng)站頭部的一些東...
摘要:哪吒社區(qū)技能樹(shù)打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁(yè)左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無(wú)意間聽(tīng)到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹(shù)打卡?【打卡貼 day2...
摘要:聲明的變量不得改變值,這意味著,一旦聲明變量,就必須立即初始化,不能留到以后賦值。 雖然今年沒(méi)有換工作的打算 但為了跟上時(shí)代的腳步 還是忍不住整理了一份最新前端知識(shí)點(diǎn) 知識(shí)點(diǎn)匯總 1.HTML HTML5新特性,語(yǔ)義化瀏覽器的標(biāo)準(zhǔn)模式和怪異模式xhtml和html的區(qū)別使用data-的好處meta標(biāo)簽canvasHTML廢棄的標(biāo)簽IE6 bug,和一些定位寫(xiě)法css js放置位置和原因...
閱讀 2424·2021-09-08 09:45
閱讀 3364·2021-09-08 09:45
閱讀 3111·2019-08-30 15:54
閱讀 3361·2019-08-26 13:54
閱讀 1418·2019-08-26 13:26
閱讀 1396·2019-08-26 13:23
閱讀 920·2019-08-23 17:57
閱讀 2190·2019-08-23 17:14