在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
每一个有数据交互的小程序,都会涉及到登录、token 等问题,openid 又是什么呢?怎么使用静默续期,来提升用户体验呢? 小程序登录登录时序一切的一切,都要从这么一张小程序登录时序图说起: 通常情况下,我们的小程序都会有业务身份,如何将微信帐号和业务身份关联起来呢?这个时候我们需要上图的步骤:
相关数据或参数上面的登录时序中,我们会涉及到一些数据和参数,先来了解下它们都是用来做啥的。 临时登录凭证 code
AppId 与 AppSecret session_key 设计 使用接口 openid unionid 加锁的登录在某些情况下,我们或许多个地方会同时触发登录逻辑(如多个接口同时拉取,发现登录态过期的情况)。一般来说,我们会简单地给请求加个锁来解决:
// session 参数 key(后台吐回) export const SESSION_KEY = 'sessionId'; let isLogining = false; export function doLogin() { return new Promise((resolve, reject) => { const session = wx.getStorageSync(SESSION_KEY); if (session) { // 缓存中有 session resolve(); } else if (isLogining) { // 正在登录中,请求轮询稍后,避免重复调用登录接口 setTimeout(() => { doLogin() .then(res => { resolve(res); }) .catch(err => { reject(err); }); }, 500); } else { isLogining = true; wx.login({ success: (res) => { if (res.code) { const reqData: ILoginRequest = { code: res.code } wx.request({ url: API.login, data: reqData, // method: "POST", success: (resp) => { const data = resp.data; isLogining = false; // 保存登录态 if (data.return_code === 0) { wx.setStorageSync(SESSION_KEY, data[SESSION_KEY]); resolve(); } else { reject(data.return_msg); } }, fail: err => { // 登录失败,解除锁,防止死锁 isLogining = false; reject(err); } }); } else { // 登录失败,解除锁,防止死锁 isLogining = false; reject(); } }, fail: (err) => { // 登录失败,解除锁,防止死锁 isLogining = false; reject(err); } }); } }); }
登录态静默续期的实现checkSession前面也提到,微信不会把 这里我们:
import {doLogin} from "./doLogin"; import {SESSION_KEY} from "./doLogin"; let isCheckingSession = false; let isSessionFresh = false; export function checkSession(): Promise<string> { return new Promise((resolve, reject) => { const session = wx.getStorageSync(SESSION_KEY); if (isCheckingSession) { setTimeout(() => { checkSession().then(res => { resolve(res); }).catch(err => { reject(err); }); }, 500); } else if (!isSessionFresh && session) { isCheckingSession = true; wx.checkSession({ success: () => { // session_key 未过期,并且在本生命周期一直有效 isSessionFresh = true; resolve(); }, fail: () => { // session_key 已经失效,需要重新执行登录流程 wx.removeStorage({ key: "skey", complete: () => { doLogin().then(() => { resolve(); }).catch(err => { reject(err); }); } }); }, complete: () => { isCheckingSession = false; } }); } else { doLogin().then(res => { resolve(res); }).catch(err => { reject(err); }); } }); } } }
静默续期的接口请求至此,我们可以封装一个简单的接口,来在每次登录态过期的时候自动续期:
import {doLogin} from "./doLogin"; import {SESSION_KEY} from "./doLogin"; import {checkSession} from "./checkSession"; // 会话过期错误码,需要重新登录 export const LOGIN_FAIL_CODES = [10000]; const TRY_LOGIN_LIMIT = 3; export function request(obj: any = {}): Promise<object> { return new Promise((resolve, reject) => { checkSession().then(() => { let session = wx.getStorageSync(SESSION_KEY); const {url, data, method, header, dataType} = obj; let tryLoginCount = obj.tryLoginCount || 0; // 如果需要通过 data 把登录态 sessionId 带上const dataWithSession = {...data, [SESSION_KEY]: session, appid: APPID}; wx.request({ url, data: dataWithSession, method, header, dataType, success: (res: any) => { if (res.statusCode === 200) { const data: ICommonResponse = res.data; // 登陆态失效特定错误码判断,且重试次数未达到上限 if (LOGIN_FAIL_CODES.indexOf(data.return_code) > -1 && tryLoginCount < TRY_LOGIN_LIMIT) { doLogin().then(() => { obj.tryLoginCount = ++tryLoginCount; request(obj).then(res => { resolve(res); }).catch(err => { reject(err); }); }); } else { resolve(res); } } else { reject(res); } }, fail: function (err) { reject(err); } }); }).catch(err => { reject(err); }); }); }
至此,我们大概包装了一个能自动登录或是进行静默续期的一个请求接口。 参考结束语小程序的登录和登录态管理,大概是大部分小程序都需要的能力。 查看Github有更多内容噢:https://github.com/godbasin 本文转载自:https://godbasin.github.io,如有侵权,请联系作者。
【PHPer技术栈】专注后端开发,倡导开源文化,做一个好玩、有趣、有灵魂的PHPer工程师,欢迎大家关注!
|
请发表评论