websocket入門(mén)案例: 構(gòu)建微信掃小程序碼登錄系統(tǒng)

websocket入門(mén)案例: 構(gòu)建微信掃小程序碼登錄系統(tǒng)

概覽

WebSocket 想必各位前后端開(kāi)發(fā)都不陌生 , 這種基于TCP的全雙工通信協(xié)議,比起 HTTP long-polling(長(zhǎng)輪詢) 來(lái)說(shuō)控制開(kāi)銷少,實(shí)時(shí)性強(qiáng)。它通過(guò) HTTP/1.1 協(xié)議的101狀態(tài)碼進(jìn)行握手。所以我們使用 nginx 這類來(lái)處理它的時(shí)候,需要配置協(xié)議升級(jí),到 HTTP/1.1版本。

而為了創(chuàng)建Websocket連接,我們通過(guò)客戶端發(fā)出請(qǐng)求,之后服務(wù)器進(jìn)行回應(yīng),這個(gè)過(guò)程通常稱為 handshaking。

案例

微信掃碼登錄,想必各位大家都不陌生,這個(gè)被廣泛應(yīng)用到了社會(huì)各個(gè)場(chǎng)景。

同時(shí)還衍生出了,微信掃公眾號(hào)二維碼登錄微信掃小程序碼登錄 , 這些本質(zhì)上原理也都大差不差。

本文就借著 微信掃小程序碼登錄 ,這個(gè)場(chǎng)景來(lái)簡(jiǎn)單聊聊 websocket 的應(yīng)用。

方案概括

簡(jiǎn)單概括一下,用戶訪問(wèn)某個(gè)網(wǎng)站, 此時(shí) 瀏覽器(ClientA) 和 WS Server 之間建立了一個(gè)長(zhǎng)鏈接, Server 給這個(gè)長(zhǎng)鏈接頒發(fā)了一個(gè) id (記為 idA) 。

ClientA 向服務(wù)端發(fā)送 idA 來(lái)請(qǐng)求小程序碼,服務(wù)端接收后,調(diào)用 wxacode.getUnlimited , 把小程序碼生成出來(lái),此小程序碼的 page 參數(shù) 為 小程序內(nèi)的websocket登錄頁(yè)面 (例如 pages/index/wsLogin), 場(chǎng)景值參數(shù) sceneidA。 生成后返回給回ClientA

接下來(lái),用戶獲取小程序碼后,使用微信掃碼,就進(jìn)入了我們小程序 (ClientB) 中的 pages/index/wsLogin 頁(yè)面,同時(shí)通過(guò)場(chǎng)景值(scene),拿到了 idA。

[圖片上傳失敗...(image-869b2f-1634381348413)]

用戶點(diǎn)擊確認(rèn)登錄,我們小程序這里,就會(huì)向服務(wù)端發(fā)送一個(gè)觸發(fā)事件(可以是ws或者http觸發(fā)),這個(gè)事件用大白話描述一下就是:
小程序這里告訴服務(wù)端 用戶微信信息xxx來(lái)驗(yàn)證登錄,同時(shí)登錄成功之后,我要向 idA 那個(gè) socket 發(fā)送一個(gè)登錄成功的事件,反之則發(fā)送未注冊(cè)事件。

瀏覽器(ClientA),檢測(cè)到這個(gè)服務(wù)端推送事件后,就能夠從服務(wù)端獲取 token,登錄并實(shí)時(shí)進(jìn)行頁(yè)面跳轉(zhuǎn)了。

是不是本質(zhì)上非常簡(jiǎn)單 ?

當(dāng)然這些作為一個(gè) demo 來(lái)說(shuō)已經(jīng)夠了, 要構(gòu)建一個(gè)高可用的遠(yuǎn)遠(yuǎn)不止。

數(shù)據(jù)交互圖

客戶端單項(xiàng)通信(掃碼登錄場(chǎng)景)

客戶端單項(xiàng)通信

客戶端雙向通信(聊天室IM場(chǎng)景)

客戶端雙向通信

(eg. 這只是最簡(jiǎn)易的場(chǎng)景,真實(shí)情況要復(fù)雜許多)

代碼實(shí)現(xiàn)

demo 為了方便, ws server 為單例,所有的 socket 實(shí)例保存在內(nèi)存中。

共有三個(gè)端,web , mp , server

demo

另一種思路

在上面這個(gè)示例中,我們給每個(gè)從客戶端連接的 ws 請(qǐng)求 頒發(fā)了一個(gè) id, 然后把它藏入小程序碼的參數(shù)里,這樣由于發(fā) id 這個(gè)機(jī)制默認(rèn)是無(wú)序的,我們比較難做緩存,萬(wàn)一依賴的第三方服務(wù) 宕機(jī),或者 運(yùn)行緩慢,勢(shì)必影響我們自身的服務(wù)。那么有沒(méi)有辦法,減小這樣的不確定性因素呢?

筆者曾經(jīng)做過(guò)一個(gè)方案:

更改指定一個(gè) socket.to namespace 里的發(fā)號(hào)規(guī)則,改為 0-999 , 然后先預(yù)制 參數(shù)為 0-999 的小程序碼共 1000 張, 把他們上傳同步到 CDN 去,并且在數(shù)據(jù)庫(kù)中記錄下他們的 id, CDN url , 這樣用戶訪問(wèn) web 端登錄頁(yè)面時(shí),發(fā)現(xiàn)是這個(gè) namespace 的規(guī)則,就按照順序,給一個(gè)沒(méi)有被占用的 id。 假設(shè)為 10 (之前9位還在保持連接)。

那么它對(duì)應(yīng)的小程序碼,就可以通過(guò) getMpQrcodeById 這樣的方式,從自己數(shù)據(jù)庫(kù)中取出鏈接,把二維碼展示在頁(yè)面上,同時(shí) 用戶通過(guò)微信掃碼后登錄,也可以進(jìn)行 client 之間 點(diǎn)對(duì)點(diǎn) 的通訊。

不過(guò)在用戶量大的時(shí)候,有可能會(huì)遇到 碼不夠用的情況,這種建議可以先預(yù)先估計(jì)用戶數(shù)量生碼,或者構(gòu)建一個(gè) job 檢測(cè)發(fā)碼數(shù)量,實(shí)時(shí)生碼,插入數(shù)據(jù)庫(kù),上傳CDN,并刷新 ws 發(fā)號(hào)規(guī)則。

擴(kuò)展后如圖所示:

qrcode-ws-with-less-third

擴(kuò)展閱讀

多實(shí)例模式

在多進(jìn)程或者集群下如何處理呢? 比如 ClientAServerA, ClientBServer B ,他們這 2 個(gè) Client 之間要如何進(jìn)行通信呢?

  1. 一種還是以單例網(wǎng)關(guān)的形式,構(gòu)建一個(gè)注冊(cè)中心負(fù)責(zé)統(tǒng)一的收發(fā)調(diào)度,然后把邏輯運(yùn)算交給其他的運(yùn)算服務(wù)去做。
  2. 另一種是構(gòu)建一套 發(fā)布/訂閱機(jī)制 (比如 redisPub/Sub mechanism) , 來(lái)保證多個(gè) ws 服務(wù),可以進(jìn)行相互通信。

協(xié)議對(duì)應(yīng):

http -> ws
https -> wss

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容