consumer-app/api/index.js

320 lines
8.8 KiB
JavaScript
Raw Normal View History

2025-12-19 12:27:55 +00:00
/**
* 接口请求封装
* 统一处理请求拦截响应拦截错误处理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)
}
})
})
}