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
|