微信小程序接口调用:未登录和登录后如何正确处理异步请求
在微信小程序开发过程中,接口请求的处理是核心功能之一,尤其是涉及用户登录状态的场景。未登录状态下发起某些需要鉴权的接口请求,或者登录完成后需要补发之前被拦截的请求,都需要合理的异步请求管理方案。本文将详细介绍未登录和登录后异步请求的处理逻辑与实现方法。
核心场景分析
实际开发中常见的两类场景需要重点处理:
用户在未登录状态下发起需要登录权限的接口请求,此时需要暂时缓存请求,引导用户登录后再重新执行
用户登录完成获取凭证后,需要自动处理之前缓存的待执行请求,同时保证后续请求的鉴权信息正确携带
基础请求封装
首先我们需要对微信小程序的wx.request进行封装,统一处理请求头、错误处理等逻辑,为后续处理登录状态相关逻辑打好基础。
// utils/request.js
const baseUrl = 'https://www.ipipp.com/api'
// 存储待执行的请求队列
let waitRequestQueue = []
// 是否正在登录中,避免重复触发登录逻辑
let isLoginning = false
/**
* 基础请求方法
* @param {Object} options 请求配置
* @returns {Promise} 请求结果的Promise
*/
const request = (options) => {
return new Promise((resolve, reject) => {
const token = wx.getStorageSync('token')
const header = {
'Content-Type': 'application/json',
...options.header
}
// 如果有token则携带鉴权头
if (token) {
header['Authorization'] = `Bearer ${token}`
}
wx.request({
url: `${baseUrl}${options.url}`,
method: options.method || 'GET',
data: options.data || {},
header,
success: (res) => {
// 401状态码表示未登录或token失效
if (res.statusCode === 401) {
// 将当前请求加入等待队列
return enqueueRequest(options, resolve, reject)
}
if (res.statusCode === 200) {
resolve(res.data)
} else {
reject(res.data)
}
},
fail: (err) => {
reject(err)
}
})
})
}
export default request未登录状态请求处理
当接口返回401未授权状态时,说明用户未登录或者登录凭证失效,此时需要将当前请求暂存到队列中,同时触发登录流程。
// 将请求加入等待队列,并触发登录
const enqueueRequest = (options, resolve, reject) => {
// 将请求的resolve和reject也存入队列,后续登录完成后直接调用
waitRequestQueue.push({
options,
resolve,
reject
})
// 如果已经在登录中,不需要重复触发登录
if (!isLoginning) {
isLoginning = true
doLogin()
}
}登录流程实现
微信小程序登录需要通过wx.login获取临时code,再调用后端登录接口换取登录凭证(token),登录完成后处理之前缓存的请求队列。
// 执行登录逻辑
const doLogin = () => {
wx.login({
success: (loginRes) => {
if (loginRes.code) {
// 调用后端登录接口,这里的接口地址使用示例域名
wx.request({
url: 'https://www.ipipp.com/api/login',
method: 'POST',
data: {
code: loginRes.code
},
success: (res) => {
if (res.statusCode === 200) {
const token = res.data.token
// 存储token到本地
wx.setStorageSync('token', token)
// 登录完成,处理等待队列中的请求
processQueue()
} else {
// 登录失败,拒绝所有等待的请求
processQueue(new Error('登录失败'))
}
},
fail: (err) => {
processQueue(err)
},
complete: () => {
isLoginning = false
}
})
} else {
isLoginning = false
processQueue(new Error('获取登录code失败'))
}
},
fail: () => {
isLoginning = false
processQueue(new Error('登录接口调用失败'))
}
})
}登录后队列请求处理
登录成功或失败后,需要对之前缓存的请求队列执行对应操作:登录成功则重新发起所有缓存的请求,登录失败则统一返回错误。
// 处理等待队列
const processQueue = (error) => {
// 遍历队列中的所有请求
waitRequestQueue.forEach((item) => {
if (error) {
// 如果有错误,直接reject请求
item.reject(error)
} else {
// 重新发起请求,将结果传给之前的resolve
request(item.options).then(item.resolve).catch(item.reject)
}
})
// 清空队列
waitRequestQueue = []
}使用示例
封装完成后,业务层中调用请求的方式和正常请求一致,不需要额外处理登录逻辑,框架会自动处理未登录场景的请求缓存和重新执行。
// pages/index/index.js
import request from '../../utils/request'
Page({
getUserInfo() {
request({
url: '/user/info',
method: 'GET'
}).then((res) => {
console.log('用户信息:', res)
}).catch((err) => {
console.error('获取用户信息失败:', err)
})
}
})注意事项
登录状态判断需要根据后端接口的实际返回状态码调整,不一定是401,部分后端可能返回200但业务码标识未登录
本地存储的token需要设置过期时间,过期后需要主动触发重新登录逻辑
如果同时发起多个需要登录的请求,队列机制可以避免重复触发多次登录流程,提升用户体验
对于不需要登录的公共接口,可以在请求封装中增加白名单配置,跳过401状态的处理