websocket入門案例: 構(gòu)建微信掃小程序碼登錄系統(tǒng)
概覽
WebSocket
想必各位前后端開發(fā)都不陌生 , 這種基于TCP的全雙工通信協(xié)議,比起 HTTP long-polling
(長輪詢) 來說控制開銷少,實(shí)時性強(qiáng)闷愤。它通過 HTTP/1.1
協(xié)議的101狀態(tài)碼進(jìn)行握手随闽。所以我們使用 nginx
這類來處理它的時候,需要配置協(xié)議升級肝谭,到 HTTP/1.1
版本。
而為了創(chuàng)建Websocket連接蛾扇,我們通過客戶端發(fā)出請求攘烛,之后服務(wù)器進(jìn)行回應(yīng),這個過程通常稱為 handshaking
镀首。
案例
微信掃碼登錄坟漱,想必各位大家都不陌生,這個被廣泛應(yīng)用到了社會各個場景更哄。
同時還衍生出了芋齿,微信掃公眾號二維碼登錄 和 微信掃小程序碼登錄 , 這些本質(zhì)上原理也都大差不差腥寇。
本文就借著 微信掃小程序碼登錄
,這個場景來簡單聊聊 websocket
的應(yīng)用觅捆。
方案概括
簡單概括一下赦役,用戶訪問某個網(wǎng)站, 此時 瀏覽器(ClientA
) 和 WS Server
之間建立了一個長鏈接, Server
給這個長鏈接頒發(fā)了一個 id
(記為 idA
) 。
ClientA
向服務(wù)端發(fā)送 idA
來請求小程序碼栅炒,服務(wù)端接收后掂摔,調(diào)用 wxacode.getUnlimited
, 把小程序碼生成出來,此小程序碼的 page
參數(shù) 為 小程序內(nèi)的websocket登錄頁面
(例如 pages/index/wsLogin
), 場景值參數(shù) scene
為 idA
赢赊。 生成后返回給回ClientA
乙漓。
接下來,用戶獲取小程序碼后释移,使用微信掃碼叭披,就進(jìn)入了我們小程序 (ClientB
) 中的 pages/index/wsLogin
頁面,同時通過場景值(scene
)玩讳,拿到了 idA
涩蜘。
[圖片上傳失敗...(image-869b2f-1634381348413)]
用戶點(diǎn)擊確認(rèn)登錄,我們小程序這里锋边,就會向服務(wù)端發(fā)送一個觸發(fā)事件(可以是ws
或者http
觸發(fā))皱坛,這個事件用大白話描述一下就是:
小程序這里告訴服務(wù)端 用戶微信信息xxx來驗(yàn)證登錄,同時登錄成功之后豆巨,我要向 idA
那個 socket
發(fā)送一個登錄成功的事件剩辟,反之則發(fā)送未注冊事件。
瀏覽器(ClientA
)往扔,檢測到這個服務(wù)端推送事件后贩猎,就能夠從服務(wù)端獲取 token
,登錄并實(shí)時進(jìn)行頁面跳轉(zhuǎn)了萍膛。
是不是本質(zhì)上非常簡單 吭服?
當(dāng)然這些作為一個 demo
來說已經(jīng)夠了, 要構(gòu)建一個高可用的遠(yuǎn)遠(yuǎn)不止。
數(shù)據(jù)交互圖
客戶端單項(xiàng)通信(掃碼登錄場景)
客戶端雙向通信(聊天室IM場景)
(eg. 這只是最簡易的場景蝗罗,真實(shí)情況要復(fù)雜許多)
代碼實(shí)現(xiàn)
此 demo
為了方便艇棕, ws server
為單例,所有的 socket
實(shí)例保存在內(nèi)存中串塑。
共有三個端沼琉,web
, mp
, server
另一種思路
在上面這個示例中,我們給每個從客戶端連接的 ws
請求 頒發(fā)了一個 id
, 然后把它藏入小程序碼的參數(shù)里桩匪,這樣由于發(fā) id
這個機(jī)制默認(rèn)是無序的打瘪,我們比較難做緩存,萬一依賴的第三方服務(wù) 宕機(jī)
,或者 運(yùn)行緩慢
闺骚,勢必影響我們自身的服務(wù)彩扔。那么有沒有辦法,減小這樣的不確定性因素呢僻爽?
筆者曾經(jīng)做過一個方案:
更改指定一個 socket.to namespace
里的發(fā)號規(guī)則虫碉,改為 0-999
, 然后先預(yù)制 參數(shù)為 0-999
的小程序碼共 1000
張, 把他們上傳同步到 CDN
去,并且在數(shù)據(jù)庫中記錄下他們的 id
, CDN url
, 這樣用戶訪問 web
端登錄頁面時进泼,發(fā)現(xiàn)是這個 namespace
的規(guī)則蔗衡,就按照順序,給一個沒有被占用的 id
乳绕。 假設(shè)為 10
(之前9位還在保持連接)绞惦。
那么它對應(yīng)的小程序碼,就可以通過 getMpQrcodeById
這樣的方式洋措,從自己數(shù)據(jù)庫中取出鏈接济蝉,把二維碼展示在頁面上,同時 用戶通過微信掃碼后登錄菠发,也可以進(jìn)行 client
之間 點(diǎn)對點(diǎn) 的通訊王滤。
不過在用戶量大的時候,有可能會遇到 碼不夠用的情況滓鸠,這種建議可以先預(yù)先估計(jì)用戶數(shù)量生碼雁乡,或者構(gòu)建一個 job
檢測發(fā)碼數(shù)量,實(shí)時生碼糜俗,插入數(shù)據(jù)庫踱稍,上傳CDN,并刷新 ws 發(fā)號規(guī)則悠抹。
擴(kuò)展后如圖所示:
擴(kuò)展閱讀
多實(shí)例模式
在多進(jìn)程或者集群下如何處理呢珠月? 比如 ClientA
連 ServerA
, ClientB
連 Server B
,他們這 2
個 Client
之間要如何進(jìn)行通信呢?
- 一種還是以單例網(wǎng)關(guān)的形式楔敌,構(gòu)建一個注冊中心負(fù)責(zé)統(tǒng)一的收發(fā)調(diào)度啤挎,然后把邏輯運(yùn)算交給其他的運(yùn)算服務(wù)去做。
- 另一種是構(gòu)建一套
發(fā)布/訂閱機(jī)制
(比如redis
的Pub/Sub mechanism
) , 來保證多個 ws 服務(wù)卵凑,可以進(jìn)行相互通信庆聘。
協(xié)議對應(yīng):
http
-> ws
https
-> wss