/** * 接口请求封装 * 统一处理请求拦截、响应拦截、错误处理、token管理等 */ // 基础URL配置(注意:末尾不要加斜杠) const BASE_URL = 'https://siji.chenjuncn.top' // 是否正在刷新token(防止并发刷新) let isRefreshing = false // 等待刷新完成的请求队列 let refreshSubscribers = [] /** * 刷新token * @param {String} refreshToken 刷新令牌 * @returns {Promise} 返回刷新结果 */ function refreshAccessToken(refreshToken) { if (isRefreshing) { // 如果正在刷新,返回一个Promise,等待刷新完成 return new Promise((resolve, reject) => { refreshSubscribers.push({ resolve, reject }) }) } isRefreshing = true return new Promise((resolve, reject) => { // 构建完整URL const fullUrl = `${BASE_URL}/app-api/member/auth/refresh` // 构建请求头 const requestHeader = { 'Content-Type': 'application/json', 'tenant-id': '1' } // 发起刷新请求 uni.request({ url: fullUrl, method: 'POST', data: { refreshToken }, header: requestHeader, success: (res) => { if (res.statusCode === 200 && res.data) { // 处理响应数据 const responseData = res.data if (responseData.code === 0 || responseData.code === 200) { const data = responseData.data || responseData // 保存新的token const token = data?.accessToken || data?.token || data?.access_token if (token) { uni.setStorageSync('token', token) } // 保存新的refreshToken(如果有) const newRefreshToken = data?.refreshToken if (newRefreshToken) { uni.setStorageSync('refreshToken', newRefreshToken) } // 保存新的过期时间 const expiresTime = data?.expiresTime if (expiresTime) { uni.setStorageSync('tokenExpiresTime', expiresTime) } // 通知所有等待的请求 refreshSubscribers.forEach(subscriber => subscriber.resolve()) refreshSubscribers = [] isRefreshing = false resolve(data) } else { // 刷新失败 const errorMsg = responseData.message || responseData.msg || '刷新token失败' refreshSubscribers.forEach(subscriber => subscriber.reject(new Error(errorMsg))) refreshSubscribers = [] isRefreshing = false reject(new Error(errorMsg)) } } else { // 刷新失败 refreshSubscribers.forEach(subscriber => subscriber.reject(new Error('刷新token失败'))) refreshSubscribers = [] isRefreshing = false reject(new Error('刷新token失败')) } }, fail: (err) => { // 刷新失败 refreshSubscribers.forEach(subscriber => subscriber.reject(err)) refreshSubscribers = [] isRefreshing = false reject(err) } }) }) } /** * 统一请求方法 * @param {Object} options 请求配置 * @param {String} options.url 请求地址(相对路径,会自动拼接BASE_URL) * @param {String} options.method 请求方法,默认GET * @param {Object} options.data 请求参数 * @param {Object} options.header 请求头 * @param {Boolean} options.showLoading 是否显示loading,默认false * @param {Boolean} options.needAuth 是否需要token认证,默认true * @returns {Promise} 返回处理后的响应数据 */ export function request(options = {}) { return new Promise((resolve, reject) => { const { url, method = 'GET', data = {}, header = {}, showLoading = false, needAuth = true } = options // 显示loading if (showLoading) { uni.showLoading({ title: '加载中...', mask: true }) } // 构建完整URL(处理BASE_URL末尾斜杠问题) const fullUrl = url.startsWith('http') ? url : `${BASE_URL}${url.startsWith('/') ? url : '/' + url}` // 构建请求头 const requestHeader = { 'Content-Type': 'application/json', 'tenant-id': '1', // 统一添加租户ID ...header } // 添加token(如果需要认证) if (needAuth) { const token = uni.getStorageSync('token') if (token) { requestHeader['Authorization'] = `Bearer ${token}` } } // 发起请求 uni.request({ url: fullUrl, method: method.toUpperCase(), data: data, header: requestHeader, success: (res) => { // 隐藏loading if (showLoading) { uni.hideLoading() } // 统一处理响应 if (res.statusCode === 200) { // 根据实际后端返回的数据结构处理 // 如果后端返回格式为 { code: 200, data: {}, message: '' } if (res.data && typeof res.data === 'object') { // 如果后端有统一的code字段 if (res.data.code !== undefined) { // 处理业务错误码401(账号未登录) if (res.data.code === 401) { // 显示登录弹窗 uni.showModal({ title: '提示', content: res.data.msg || res.data.message || '账号未登录,请前往登录', showCancel: false, confirmText: '去登录', success: (modalRes) => { if (modalRes.confirm) { // 清除本地存储的登录信息 uni.removeStorageSync('token') uni.removeStorageSync('refreshToken') uni.removeStorageSync('tokenExpiresTime') uni.removeStorageSync('userId') uni.removeStorageSync('userInfo') // 跳转到登录页面 uni.navigateTo({ url: '/pages/login/login' }) } } }) reject(new Error('未授权')) return } if (res.data.code === 200 || res.data.code === 0) { resolve(res.data.data || res.data) } else { // 业务错误 const errorMsg = res.data.message || res.data.msg || '请求失败' uni.showToast({ title: errorMsg, icon: 'none', duration: 2000 }) reject(new Error(errorMsg)) } } else { // 没有code字段,直接返回data resolve(res.data) } } else { resolve(res.data) } } else if (res.statusCode === 401) { // token过期或未登录,尝试使用refreshToken刷新 const refreshToken = uni.getStorageSync('refreshToken') if (refreshToken) { // 尝试刷新token refreshAccessToken(refreshToken) .then(() => { // 刷新成功,重新发起原请求 return request(options) }) .then(resolve) .catch(() => { // 刷新失败,显示登录弹窗 const errorMsg = res.data?.msg || res.data?.message || '账号未登录,请前往登录' uni.showModal({ title: '提示', content: errorMsg, showCancel: false, confirmText: '去登录', success: (modalRes) => { if (modalRes.confirm) { // 清除token,跳转到登录页 uni.removeStorageSync('token') uni.removeStorageSync('refreshToken') uni.removeStorageSync('tokenExpiresTime') uni.removeStorageSync('userId') uni.removeStorageSync('userInfo') uni.navigateTo({ url: '/pages/login/login' }) } } }) reject(new Error('未授权')) }) } else { // 没有refreshToken,显示登录弹窗 const errorMsg = res.data?.msg || res.data?.message || '账号未登录,请前往登录' uni.showModal({ title: '提示', content: errorMsg, showCancel: false, confirmText: '去登录', success: (modalRes) => { if (modalRes.confirm) { // 清除token,跳转到登录页 uni.removeStorageSync('token') uni.removeStorageSync('refreshToken') uni.removeStorageSync('tokenExpiresTime') uni.removeStorageSync('userId') uni.removeStorageSync('userInfo') uni.navigateTo({ url: '/pages/login/login' }) } } }) reject(new Error('未授权')) } } else if (res.statusCode >= 500) { // 服务器错误 uni.showToast({ title: '服务器错误,请稍后重试', icon: 'none' }) reject(new Error('服务器错误')) } else { // 其他错误 const errorMsg = res.data?.message || res.data?.msg || `请求失败(${res.statusCode})` uni.showToast({ title: errorMsg, icon: 'none' }) reject(new Error(errorMsg)) } }, fail: (err) => { // 隐藏loading if (showLoading) { uni.hideLoading() } // 网络错误处理 let errorMsg = '网络请求失败' if (err.errMsg) { if (err.errMsg.includes('timeout')) { errorMsg = '请求超时,请检查网络' } else if (err.errMsg.includes('fail')) { errorMsg = '网络连接失败,请检查网络设置' } } uni.showToast({ title: errorMsg, icon: 'none', duration: 2000 }) reject(err) } }) }) }