一、小程序原生能力
微信利用了自己的账号系统,给每个小程序主体提供了拿到该用户在当前主体的唯一识别码(open_id)的api: wx.login
wx.login({
success: function (res) {
if (res.code) {
callback(null, res.code)
// 拿到微信给的临时登录凭证code, 用这个code可以去服务器换成open_id
} else {
callback('登陆失败!' + res.errMsg)
}
}
})
code换open_id必须通过服务器处理,需要使用到app_secret, 文档地址:
https://developers.weixin.qq.com/miniprogram/dev/api/signature.html
二、一般登录流程
- 服务器拿到code之后,去微信服务器换成用户的当前小程序的唯一id: open_id,并生成业务的登录token,然后返回token给前端, 前端通常会将此token缓存在storage里,实现登录状态保持
let login = () => {
wx.request({
url: 'login',
code: code,
success: (data) => {
wx.setStorageSync('token', data.token)
}
})
}
- 前端在请求头里带上token
wx.request({
url: requestUrl,
data: data,
method: method,
header: {
'Authorization': `Bearer ${token}`
}
})
三、登录过期重连
当我们认为登录过期时,将未完成的请求加入队列,然后执行登录操作,登录完成之后批量执行队列里的请求
// 用于存储没有complete的请求
const reqQueue = []
// 封装一个通用的请求方法
let Rq = function (param, method, url, callback) {
let makeRequest = () = > {
let token = getStorageSync('token', token)
wx.request({
url: url,
data: param,
method: method,
header: {
'Authorization': `${token}`
},
complete: function (res) {
// 发现登录过期
if (String(res.statusCode) === '401') {
// 往队列里丢待执行的函数
reqQueue.push(makeNowRequest)
login()
return
}
callback(null, res.data)
}
})
}
makeRequest()
}
修改login函数,登录之后执行队列的函数
let login = () => {
wx.request({
url: 'login',
code: code,
success: (data) => {
wx.setStorageSync('token', data.token)
// 执行队列里的等待函数
reqQueue.forEach((item) => {
item()
})
}
})
}
这里最关键的一步就是在401发生的时候,将当时的函数执行上下文存储起来,用于登录重试后的处理。需要明白的是,在微信小程序里是没有cookie的,做数据持久化依赖的是wx.setStorage,以及重试利用回调队列的存储和释放来实现。