這裏有幾個點是要注意的:html
引用Yinjie 的圖,由於這個圖比官方的要看得明白一點。git
引用Yinjie 的圖,由於這個圖比官方的要看得明白一點。es6
引用騰訊 weapp-session 的圖github
他們還出了一個比較詳細的,一步步的代碼處理流程,能夠對比本身的程序進行檢查。
request
weapp-session-client 包裝 request
redis
首次請求算法
wx.login()
和 wx.getUserInfo()
接口得到 code
、rawData
和 signature
requset
的頭部帶上 code
、rawData
和 signature
code
供下次調用非首次請求數據庫
request
的頭部帶上保存的 code
服務器收到請求 request
,中間件從頭部提取 code
、rawData
和 signature
字段小程序
code
爲空,跳到第 4
步若是 code
不爲空,且 rawData
不爲空,須要進行簽名校驗微信小程序
使用 code
,appid
、app_secret
請求微信接口得到 session_key
和 openid
api
ERR_SESSION_KEY_EXCHANGE_FAILED
rawData
和 session_key
計算簽名 signature2
對比 signature
和 signature2
簽名一致,解析 rawData
爲 wxUserInfo
openid
寫入到 wxUserInfo
(code, wxUserInfo)
緩存到 RediswxUserInfo
存放在 request.$wxUserInfo
裏4
步ERR_UNTRUSTED_RAW_DATA
若是 code
不爲空,但 rawData
爲空,從 Redis 根據 code
查詢緩存的用戶信息
request.$wxUserInfo
字段裏,跳到第 4
步ERR_SESSION_EXPIRED
request
被業務處理,可使用 request.$wxUserInfo
來獲取用戶信息(request.$wxUserInfo
可能爲空,業務須要自行處理)code
是微信用戶的登陸憑證,打開小程序登陸的時候獲取的只屬於微信這個用戶的登陸憑證,須要注意的是,這個登陸憑證只供微信小程序使用的。session_key
是微信用戶在小程序裏面的登陸態信息,至關因而微信給這個用戶頒發的一個登陸 session,官網地址
{"session_key":"...","expires_in":7200,"openid":"..."}
,須要按期使用wx.checkSession檢測。openId
,用戶的惟一標識unioinId
,若是開發者擁有多個移動應用、網站應用、和公衆賬號(包括小程序),可經過unionid
來區分用戶的惟一性,由於只要是同一個微信開放平臺賬號下的移動應用、網站應用和公衆賬號(包括小程序),用戶的unionid
是惟一的。換句話說,同一用戶,對同一個微信開放平臺下的不一樣應用,unionid
是相同的。openId
就是微信用戶的惟一標識,可是由於微信產品不少,因此會出現多個微信產品使用不一樣的 openId
來標識用戶,可是對於咱們作業務接入的話,就買辦法使用了,因此建議是統一使用 unioinid
,由於通常來講,通常的業務都會有公衆號,小程序聯合使用的。3rd_session
是通常是指咱們本身公司的服務器的 session
,通常來講,能夠跟原來的業務的 session
一塊兒使用,不過這個 session
的過時時間必定要比小程序的session_key
的過時時間要長,這樣能夠減小 session
的屢次重複建立,另一般咱們本身公司的服務器的 session
管理都會使用相似 redis 之類的數據庫進行管理的,這個大體瞭解一下,由於其餘文章會提到。session
(session_key
和3rd_session
),那是由於session_key
是微信的登陸態,3rd_session
是咱們業務系統的登陸態,兩邊各有一個登陸態,因此須要將2個登陸態合併爲一個 session
,在這裏面是合併爲3rd_session
,並保存到咱們業務系統上,而後每次須要使用的時候,小程序帶上這個3rd_session
訪問咱們的業務系統,經過處理,能夠返回咱們須要 unioinid 和其餘 session
信息而不用每次都去獲取一個新的session_key
(由於微信有限制code 的使用,要用 code 換 session_key),總的來講,就是使用3rd_session
來管理小程序的登陸態根據官方文檔: ,數據校驗是爲了提升數據的安全性,咱們須要獲取用戶的 unioinid,須要調用wx.getUserInfo
接口來獲取,可是通常狀況下,獲取出來的數據是
{ "nickName": "Band", "gender": 1, "language": "zh_CN", "city": "Guangzhou", "province": "Guangdong", "country": "CN", "avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0" }
對於須要業務接入的話,沒有 unioinid 是沒意義的,因此須要根據官方的方式來進行解密,解密後的數據裏面有 unioinid 了
{ "openId": "OPENID", "nickName": "NICKNAME", "gender": GENDER, "city": "CITY", "province": "PROVINCE", "country": "COUNTRY", "avatarUrl": "AVATARURL", "unionId": "UNIONID", "watermark": { "appid":"APPID", "timestamp":TIMESTAMP } }
由於小程序的全部網絡請求都是異步的,那麼異步就會出現不少重的回調的問題,因此改爲了 promise,promise 的使用要謹慎注意 resolve 和 return的處理。
例如這樣:
const httpRequest = (api, data) => { let serverHost = env.serverHost; return new Promise(function (resolve, reject) { //發起網絡請求 wx.request({ url: serverHost + api, data: data, header: { 'content-type': 'application/x-www-form-urlencoded' }, success: function (res) { if (res.data.errno === 0) { // 須要下一步處理的就用 resolve 返回 resolve(res.data); } else { console.log("http fail:api:" + api + "res:" + JSON.stringify(res)); // 須要跳出循環處理的就用 reject reject(res.data); } }, fail: function (res) { console.log("http fail:api:" + api + "res:" + JSON.stringify(res)); // 須要跳出循環處理的就用 reject reject(res); } }) }) };
在多重 promise 的狀況下,則須要注意2個地方:
getCode() // 獲取 wx code .then(code => { wxCode = code; // 這裏getSetting是一個返回的 promise實例,如上面的那個 return getSetting(); // 獲取 setting }) .then(res => { if (res.authSetting["scope.userInfo"]) { // 這裏getUserInfo是一個返回的 promise實例 return getUserInfo(self); } else { console.log("first auth none:" + JSON.stringify(res)); // 相似 return util.showModal("親,尚未受權!") .then(res => { return getAuth("userInfo"); }).then(res => { // 檢查受權是否正常 return getSetting(); }) .then(res => { if (res.authSetting["scope.userInfo"]) { return getUserInfo(self); } else { return Promise.reject(res); } }); } }) .catch(err=>{ console.log("err"+err); })
微信小程序「受權失敗」場景須要優雅處理,提高用戶體驗,參考這裏:能夠稍微看到是如何生效的:
經過在wx.getSetting
裏面插入一個判斷處理,判斷沒有權限即彈出 modal 提示框:
wx.getSetting({ success: function success(res) { console.log(res.authSetting); var authSetting = res.authSetting; if (authSetting['scope.userInfo'] === false) { wx.showModal({ title: '用戶未受權', content: '如需XXXXXXX。', showCancel: false, success: function (res) { if (res.confirm) { console.log('用戶點擊肯定') wx.openSetting({ success: function success(res) { } }); } } }) } } });
參考引用: