230 lines
5.1 KiB
JavaScript
230 lines
5.1 KiB
JavaScript
import config from './config.js'
|
||
|
||
// 请求队列(用于处理token刷新)
|
||
const requestQueue = []
|
||
let isRefreshing = false
|
||
|
||
class Request {
|
||
constructor() {
|
||
this.baseURL = config.baseURL
|
||
this.timeout = config.timeout
|
||
this.interceptors = {
|
||
request: [],
|
||
response: []
|
||
}
|
||
}
|
||
|
||
// 添加请求拦截器
|
||
addRequestInterceptor(interceptor) {
|
||
this.interceptors.request.push(interceptor)
|
||
}
|
||
|
||
// 添加响应拦截器
|
||
addResponseInterceptor(interceptor) {
|
||
this.interceptors.response.push(interceptor)
|
||
}
|
||
|
||
// 执行请求拦截器
|
||
async runRequestInterceptors(config) {
|
||
for (const interceptor of this.interceptors.request) {
|
||
config = await interceptor(config)
|
||
}
|
||
return config
|
||
}
|
||
|
||
// 执行响应拦截器
|
||
async runResponseInterceptors(response) {
|
||
for (const interceptor of this.interceptors.response) {
|
||
response = await interceptor(response)
|
||
}
|
||
return response
|
||
}
|
||
|
||
// 核心请求方法
|
||
async request(options) {
|
||
try {
|
||
// 合并配置
|
||
const requestConfig = {
|
||
url: options.url.startsWith('http') ? options.url : `${this.baseURL}${options.url}`,
|
||
method: options.method || 'GET',
|
||
header: {
|
||
'Content-Type': 'application/json',
|
||
...options.header
|
||
},
|
||
data: options.data,
|
||
timeout: this.timeout
|
||
}
|
||
|
||
// 执行请求拦截器
|
||
const finalConfig = await this.runRequestInterceptors(requestConfig)
|
||
|
||
// 发起请求
|
||
const response = await uni.request(finalConfig)
|
||
|
||
// 执行响应拦截器
|
||
const finalResponse = await this.runResponseInterceptors(response)
|
||
|
||
return finalResponse[1] // uni.request返回的是数组[error, success]
|
||
} catch (error) {
|
||
console.error('Request error:', error)
|
||
throw error
|
||
}
|
||
}
|
||
|
||
// GET请求
|
||
get(url, data = {}, options = {}) {
|
||
return this.request({
|
||
url,
|
||
method: 'GET',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
// POST请求
|
||
post(url, data = {}, options = {}) {
|
||
return this.request({
|
||
url,
|
||
method: 'POST',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
// PUT请求
|
||
put(url, data = {}, options = {}) {
|
||
return this.request({
|
||
url,
|
||
method: 'PUT',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
// DELETE请求
|
||
delete(url, data = {}, options = {}) {
|
||
return this.request({
|
||
url,
|
||
method: 'DELETE',
|
||
data,
|
||
...options
|
||
})
|
||
}
|
||
|
||
// 上传文件
|
||
upload(url, filePath, formData = {}, options = {}) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.uploadFile({
|
||
url: `${this.baseURL}${url}`,
|
||
filePath,
|
||
name: 'file',
|
||
formData,
|
||
success: resolve,
|
||
fail: reject,
|
||
...options
|
||
})
|
||
})
|
||
}
|
||
|
||
// 下载文件
|
||
download(url, options = {}) {
|
||
return new Promise((resolve, reject) => {
|
||
uni.downloadFile({
|
||
url: `${this.baseURL}${url}`,
|
||
success: resolve,
|
||
fail: reject,
|
||
...options
|
||
})
|
||
})
|
||
}
|
||
}
|
||
|
||
// 创建请求实例
|
||
const request = new Request()
|
||
|
||
// 添加请求拦截器 - Token处理
|
||
request.addRequestInterceptor(async (config) => {
|
||
const token = uni.getStorageSync('token')
|
||
if (token) {
|
||
config.header.Authorization = `Bearer ${token}`
|
||
}
|
||
return config
|
||
})
|
||
|
||
// 添加响应拦截器 - 错误处理
|
||
request.addResponseInterceptor(async (response) => {
|
||
const { statusCode, data } = response
|
||
|
||
if (statusCode === 200) {
|
||
if (data.code === 0) {
|
||
return data.data
|
||
} else {
|
||
// 业务错误
|
||
const error = new Error(data.message || '业务错误')
|
||
error.code = data.code
|
||
throw error
|
||
}
|
||
} else if (statusCode === 401) {
|
||
// Token过期,尝试刷新
|
||
return handleTokenExpired(response)
|
||
} else {
|
||
// 网络错误
|
||
throw new Error(`网络错误: ${statusCode}`)
|
||
}
|
||
})
|
||
|
||
// Token过期处理
|
||
async function handleTokenExpired(response) {
|
||
if (isRefreshing) {
|
||
// 如果正在刷新,将请求加入队列
|
||
return new Promise((resolve) => {
|
||
requestQueue.push(() => resolve(request.request(response.config)))
|
||
})
|
||
}
|
||
|
||
isRefreshing = true
|
||
const refreshToken = uni.getStorageSync('refreshToken')
|
||
|
||
if (!refreshToken) {
|
||
// 没有refreshToken,跳转到登录页
|
||
uni.navigateTo({ url: '/pages/auth/login' })
|
||
throw new Error('请重新登录')
|
||
}
|
||
|
||
try {
|
||
// 尝试刷新Token
|
||
const result = await request.post(config.endpoints.USER.REFRESH_TOKEN, {
|
||
refreshToken
|
||
})
|
||
|
||
// 保存新Token
|
||
uni.setStorageSync('token', result.token)
|
||
uni.setStorageSync('refreshToken', result.refreshToken)
|
||
|
||
// 重试原始请求
|
||
const retryResponse = await request.request(response.config)
|
||
|
||
// 处理队列中的请求
|
||
processRequestQueue()
|
||
|
||
return retryResponse
|
||
} catch (error) {
|
||
// 刷新失败,清空Token并跳转登录
|
||
uni.removeStorageSync('token')
|
||
uni.removeStorageSync('refreshToken')
|
||
uni.navigateTo({ url: '/pages/auth/login' })
|
||
throw error
|
||
} finally {
|
||
isRefreshing = false
|
||
}
|
||
}
|
||
|
||
// 处理请求队列
|
||
function processRequestQueue() {
|
||
while (requestQueue.length > 0) {
|
||
const retry = requestQueue.shift()
|
||
retry()
|
||
}
|
||
}
|
||
|
||
export default request |