Files
jiebanke/mini-program/api/request.js
2025-08-30 14:33:49 +08:00

230 lines
5.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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