小程序版 websocket 聊天室。 從服務(wù)器到小程序客戶端配置基礎(chǔ)教程。
在本教程內(nèi)我們將在小程序內(nèi)實(shí)現(xiàn)一個(gè)基本的 websocket 聊天室, 計(jì)劃實(shí)現(xiàn)以下功能:
小程序已掛,原因是個(gè)人開(kāi)發(fā)者無(wú)法提交信息交流類小程序, 不過(guò)在本地運(yùn)行 demo 還是沒(méi)問(wèn)題的。
寫(xiě)的有紕漏的地方還請(qǐng)大家指出,在 SF 下留言或在 本項(xiàng)目 git 內(nèi)提 issue ,我們一起進(jìn)步 ^o^
小程序端的聊天室信息流其實(shí)非常簡(jiǎn)單, 而本教程就借助一個(gè)好玩兒的小程序聊天室來(lái)進(jìn)一步理解小程序中的 session 實(shí)現(xiàn)。
我在服務(wù)器端環(huán)境搭建及配置主要參考騰訊云實(shí)驗(yàn) 基于 CentOS 搭建微信小程序服務(wù)
我們?cè)诖讼纫斫庑〕绦蚨藶楹螣o(wú)法實(shí)現(xiàn) session, 以及如何在小程序?qū)崿F(xiàn) websocket 通信。
小程序并非嵌套在微信內(nèi)的 html5 網(wǎng)頁(yè), 它并不是從 url 訪問(wèn)到的。 我們只能自己實(shí)現(xiàn)類似會(huì)話的東西, 好在官方已經(jīng)提供了相應(yīng)的套件來(lái)實(shí)現(xiàn) session。 即 wafer-client-sdk 和 node 中間件 wafer-node-session , 我們依照文檔就能簡(jiǎn)單地實(shí)現(xiàn) session。
騰訊云 wafer 項(xiàng)目下有很多相似項(xiàng)目「大部分需要配合騰訊云進(jìn)行一鍵部署」, 如果我們只需要實(shí)現(xiàn)小程序 session 管理的話, wafer-client-sdk 和 node 中間件 wafer-node-session 即可。
在服務(wù)器端我們使用了 ws 包來(lái)實(shí)現(xiàn) websocket ,沒(méi)有使用 socket.io 的原因是 socket.io 需要客戶端有額外的腳本才能實(shí)現(xiàn)通信。
在小程序端我們引入 wafer-client-sdk 套件使服務(wù)器可以獲取 session。
主要邏輯分為幾個(gè)簡(jiǎn)單函數(shù), 當(dāng)然你需要先配置請(qǐng)求的服務(wù)器域名和小程序賬號(hào)密碼。
// 引入 session 套件, 里面封裝了 wx.login, wx.getUserInfo 等操作 const wafer = require('../../vendors/wafer-client-sdk/index') // 用于登錄使服務(wù)器獲得 session, 然后服務(wù)器返回的 session 里就會(huì)包含用戶信息了, 用來(lái)在 websocket 里返回發(fā)信息用戶的頭像 url function login(){ ..... } // 用于有新信息時(shí)更新數(shù)據(jù), msg 指信息, ad 指 websocket 傳回的信息 id, 用于 scroll-into-view 滾動(dòng) pushMsg(msg, ad) { ..... } // 用于監(jiān)聽(tīng) websocket 連接 listen(){ ..... } // 用于小程序發(fā)送 websocket 信息 send(){ ..... }
基本就是這些, 關(guān)于 websocket 通信過(guò)程是這樣的:
當(dāng)然最開(kāi)始是要與服務(wù)器端 websocket 連接的, 只有每個(gè)連接了的客戶端才可以交流信息。
對(duì)于 session 的實(shí)現(xiàn)我們?cè)诜?wù)器端使用了 wafer-node-session 即為連接提供 session 能力。 在小程序端我們配套使用了 wafer-client-sdk , 這里面封裝了 wx.request、 wx.login 等邏輯, 實(shí)現(xiàn)了小程序端的用戶登錄、session 設(shè)置。
關(guān)于小程序端的 session 獲取問(wèn)題主要有如下幾個(gè)步驟
在我們的 demo 中就出現(xiàn)了服務(wù)器 session 已經(jīng)過(guò)期而本地 session 還沒(méi)過(guò)期的情況。 而 websocket 每次發(fā)送信息都需要從 req.session 內(nèi)獲取用戶頭像, 所以會(huì)導(dǎo)致 websocket 連接失敗。 但是在小程序端 session 未過(guò)期,即在服務(wù)器端的 sessionKey 和小程序的 sessionKey 不一致了 「客戶端 sessionKey 還在而服務(wù)器的 sessionKey 已經(jīng)過(guò)期銷毀」, 導(dǎo)致比對(duì)失敗。 那怎么辦呢? 重新請(qǐng)求唄! 但是因?yàn)?wafer 封裝了 session 管理 「小程序端 session 過(guò)期后才會(huì)重新請(qǐng)求」 存在 session 緩存的緣故, 小程序并沒(méi)有重新發(fā)送信息給自己的服務(wù)器進(jìn)而生成新的 sessionKey, 所以我們?cè)诿恳淮?wx.sendSocketMessage 發(fā)信息的時(shí)候都要檢查服務(wù)器端的 session 情況, 這里需要做簡(jiǎn)單的判斷「websocket 信息有錯(cuò)誤就清除本地 session」讓小程序重新請(qǐng)求服務(wù)器。
既然要發(fā)送信息「即產(chǎn)生數(shù)據(jù)」, 那么這些信息都儲(chǔ)存在哪里呢? 在發(fā)送文本信息時(shí), 服務(wù)器端收到數(shù)據(jù)后只做簡(jiǎn)單地處理便返回給小程序, 這時(shí)的數(shù)據(jù)應(yīng)該是儲(chǔ)存在服務(wù)器內(nèi)存中。 因?yàn)?websocket 在收到請(qǐng)求后簡(jiǎn)單處理了字符串信息直接返回給小程序, 那我們發(fā)送其它富媒體信息時(shí),也可以以二進(jìn)制的方式發(fā)送給 websocket 服務(wù)器, 然后重新返回給客戶端 「即 websocket 只做文件中轉(zhuǎn)」,相關(guān)實(shí)現(xiàn) websocket-stream 。 貌似看起來(lái)很復(fù)雜,在這里我使用了國(guó)內(nèi)的 paas 服務(wù)商 leanCloud 的儲(chǔ)存服務(wù) 「即小程序端把發(fā)送的文件儲(chǔ)存在云端,返回一個(gè)文件地址」,然后我們把這個(gè)文件信息進(jìn)行標(biāo)注「即只發(fā)送文件的 url 信息, 小程序端判斷請(qǐng)求是否是文件進(jìn)而顯示」。 當(dāng)然你也可以發(fā)送視頻或者音頻, 把他們都保存在云端, 只發(fā)送其相應(yīng)的 url 即可。 我們這里的 websocket 服務(wù)器只做一個(gè)文件中轉(zhuǎn)的功能, 而文件的存儲(chǔ)交給云端來(lái)負(fù)責(zé)。
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)