登錄時序圖
下圖是小程序官方文檔中的登錄時序圖。此圖涵蓋了前后端,詳細講解了包括登錄態(tài)的生成,維護,傳輸?shù)雀鞣矫娴膯栴}。
發(fā)起網(wǎng)絡(luò)請求的流程圖 具體到業(yè)務(wù)開發(fā)過程中的前端來說,我認為上圖還不夠完整,于是我畫了下面這張以前端邏輯為出發(fā)點的、包含循環(huán)的流程圖。 我認為前端每一次發(fā)起網(wǎng)絡(luò)請求,跟后臺進行數(shù)據(jù)交互,都適用于下圖的流程:
只要遵循上圖的流程,我們就無需在業(yè)務(wù)邏輯中關(guān)注登錄態(tài)的問題了,相當于把登錄態(tài)的管理問題耦合到了發(fā)起網(wǎng)絡(luò)請求當中。 一般情況下,我們程序設(shè)計都會遵循模塊解耦的原則,盡可能將模塊顆粒化到最小。這導(dǎo)致可能有些同學(xué)認為模塊耦合不是好事情,但是我認為這是要分情況的:
以上兩點雖然是登錄態(tài)管理的問題,但從另外一個角度去理解,我更認為它是小程序網(wǎng)絡(luò)請求的能力問題,所以,我認為通過拓展小程序網(wǎng)絡(luò)請求能力來實現(xiàn)登錄態(tài)的自動管理是非常合適的。通用組件——weRequest 一個通過拓展wx.request,從而實現(xiàn)自動管理登錄態(tài)的組件。 先來看看怎么使用: var weRequest= require('../weRequest'); // 初始化配置 weRequest.init({ // 關(guān)于配置內(nèi)容,將在后文詳述 // 此處暫時省略... }) // 發(fā)起請求 weRequest.request({ url: 'order/detail', data: { id: '107B7615E04AE64CFC10' }, success: function (data) { // 省略... } })
我們來看看執(zhí)行上面代碼的DEMO效果:
可以看到,通過weRequest發(fā)出的請求,將會自動帶上登錄態(tài)參數(shù)。 對應(yīng)的流程為下圖中紅色的指向: 那如果當前小程序并沒有登錄態(tài)的情況又會如何呢? 接下來我們來看看本地?zé)o登錄態(tài)情況下的模擬: 當本地沒有登錄態(tài)時,按照流程圖,weRequest將會自動執(zhí)行wx.login()后的一系列流程,得到code并調(diào)用后臺接口換取session,儲存在localStorage之后,重新發(fā)起業(yè)務(wù)請求。 對應(yīng)的流程為下圖中紅色的指向: 登錄態(tài)過期時,自動重新登錄 接下來我們再來看看,當本地儲存的登錄態(tài)過期之后,頁面的行為如何:
對后臺數(shù)據(jù)進行預(yù)解析之后,發(fā)現(xiàn)登錄態(tài)過期,于是重新執(zhí)行登錄流程,獲取新的session之后,重新發(fā)起請求。 對應(yīng)的流程為下圖中紅色的指向: weRequest提供一個init方法,用于對組件的配置,以下展示所有的配置項: weRequest.init({ // 儲存在localStorage的session名稱,且CGI請求的data中會自動帶上以此為名稱的session值;可不傳,默認為session sessionName: "session", // 請求URL的固定前綴;可不傳,默認為空 urlPerfix: "https://www.example.com/", // 觸發(fā)重新登錄的條件,res為CGI返回的數(shù)據(jù) loginTrigger: function (res) { // 此處例子:當返回數(shù)據(jù)中的字段errcode等于-1,會自動觸發(fā)重新登錄 return res.errcode == -1; }, // 用code換取session的CGI配置 codeToSession: { // CGI的URL url: 'user/login', // 調(diào)用改CGI的方法;可不傳,默認為GET method: 'GET', // CGI中傳參時,存放code的名稱,此處例子名稱就是code;可不傳,默認值為code codeName: 'code', // CGI中返回的session值 success: function (res) { // 此處例子:CGI返回數(shù)據(jù)中的字段session即為session值 return res.session; } }, // 登錄重試次數(shù),當連續(xù)請求登錄接口返回失敗次數(shù)超過這個次數(shù),將不再重試登錄 reLoginLimit: 2, // 觸發(fā)請求成功的條件 successTrigger: function (res) { // 此處例子:當返回數(shù)據(jù)中的字段errcode等于0時,代表請求成功,其他情況都認為業(yè)務(wù)邏輯失敗 return res.errcode == 0; }, // 成功之后返回數(shù)據(jù);可不傳 successData: function (res) { // 此處例子:返回數(shù)據(jù)中的字段data為業(yè)務(wù)接受到的數(shù)據(jù) return res.data; }, // 當CGI返回錯誤時,彈框提示的標題文字 errorTitle: function(res) { // 此處例子:當返回數(shù)據(jù)中的字段errcode等于0x10040730時,錯誤彈框的標題是“溫馨提示”,其他情況下則是“操作失敗” return res.errcode == 0x10040730 ? '溫馨提示' : '操作失敗' }, // 當CGI返回錯誤時,彈框提示的內(nèi)容文字 errorContent: function(res) { // 此處例子:返回數(shù)據(jù)中的字段msg為錯誤彈框的提示內(nèi)容文字 return res.msg } })讓業(yè)務(wù)邏輯更專注,不用再關(guān)注底層登錄態(tài)問題 小程序?qū)Ρ纫酝腍5,登錄態(tài)管理邏輯要復(fù)雜很多。通過weRequest這個組件,希望能幫助開發(fā)者把更多精力放在業(yè)務(wù)邏輯上,而登錄態(tài)管理問題只需通過一次簡單配置,以后就不用再花精力管理了。FAQ我希望在請求時候,頁面能出現(xiàn)最簡單的loading狀態(tài),該怎么辦? 只需要在請求的時候,加上參數(shù)showLoading: true即可,如: weRequest.request({ url: 'order/detail', showLoading: true, data: { id: '123' }, success: function (data) { console.log(data); } }) 當然,如果你希望使用個性化的loading樣式,你可以直接使用beforeSend參數(shù)來進行自定義展示個性化的loading,并且在complete的時候?qū)⑺[藏。某些請求在返回錯誤時,我不希望觸發(fā)通用的錯誤提示框,而想用特別的邏輯去處理,該怎么辦? 只需要在請求的時候,加上參數(shù)fail: function(){ ... }即可,如: weRequest.request({ url: 'order/detail', slience: true, data: { id: '123' }, success: function (data) { console.log(data); }, fail: function(res) { console.log(res); } }) 此時,如果接口返回錯誤碼,將觸發(fā)這里定義的fail函數(shù),且默認錯誤彈框?qū)⒉粫霈F(xiàn)。為什么工具在發(fā)起請求之前,不主動去判斷第三方session是否過期,而要通過接口結(jié)果來判斷,這不是浪費了一次請求往返嗎? 每個小程序?qū)τ谧陨砩傻膕ession都有自己的一套管理方案,微信官方也沒有指明一套通用的方案來要求開發(fā)者,僅僅要求了應(yīng)該保證其安全性且不應(yīng)該設(shè)置較長的過期時間。 原文如下:
因此,不能要求所有后端接口都要返回session的過期時間給前端,甚至有些后端邏輯對于session的管理是動態(tài)的,會隨調(diào)用情況來更新session的生命周期,這樣的話邏輯就更復(fù)雜了。但是無論任何一種管理策略,都必須會有兜底策略,即前端傳入過期的session,后端必須要返回特定標識告知前端此session過期。
因此作為一個通用的工具組件,我需要確保更多的開發(fā)者能夠低門檻地使用,所以并沒有針對各種特別策略去優(yōu)化,而且我相信,對于正常使用小程序的用戶來說,登錄態(tài)過期是一個相對低概率的事情,對整體效率性能來說,是微乎其微的,使用通用的兜底策略去應(yīng)對這種情況,我認為已經(jīng)是足夠的了。 |
工作日 8:30-12:00 14:30-18:00
周六及部分節(jié)假日提供值班服務(wù)