javascript
复制代码
// request.js
import {
getApptoken,
getStoredApptoken
} from './tokenRequest' // 从合并模块导入
// 全局配置
const MAX_RETRIES = 1 // 最大重试次数
const baseURL = 'https://your-api.com'
// 请求队列和刷新状态
let requestsQueue = []
let isRefreshing = false
// 核心请求函数
export const request = config => {
return new Promise((resolve, reject) => {
// 应用请求拦截器
const processedConfig = requestInterceptor({
baseURL,
method: 'POST',
needRefreshToken: true,
retryCount: 0, // 记录重试次数
...config
})
// 处理参数拼接(原URL有参数则用&,否则用?)
const separator = processedConfig.url.includes('?') ? '&' : '?'
const url = `${processedConfig.baseURL}${processedConfig.url}${separator}token=${processedConfig.apptoken || ''}`
// 发起请求
uni.request({
...processedConfig,
url,
success: response => {
// 应用响应拦截器
responseInterceptor(response, processedConfig)
.then(resolvedData => resolve(resolvedData))
.catch(err => reject(err))
},
fail: error => {
console.error(`请求失败:${processedConfig.url}`, error)
reject(error)
}
})
})
}
// 请求拦截器:统一处理请求前逻辑
const requestInterceptor = config => {
config.header = {
'Content-Type': 'application/json',
...config.header
}
if (config.needRefreshToken) {
const token = getStoredApptoken() // 使用合并模块的工具函数
if (token) {
config.token = token
}
}
return config
}
// 响应拦截器:统一处理响应后逻辑
const responseInterceptor = async (response, config) => {
const {
data,
statusCode
} = response
// 处理成功响应
if (statusCode === 200) {
return data
}
// 处理401/400错误(token过期)
if ((statusCode === 401 || statusCode === 400) && config.needRefreshToken) {
// 检查是否超过最大重试次数
if (config.retryCount >= MAX_RETRIES) {
uni.showToast({
title: '重试次数过多,请稍后再试',
icon: 'none'
})
return Promise.reject(new Error('重试次数过多'))
}
// 如果正在刷新token,将请求加入队列等待
if (isRefreshing) {
return new Promise(resolve => {
requestsQueue.push(() => resolve(request({
...config,
retryCount: config.retryCount + 1
})))
})
}
// 开始刷新token
isRefreshing = true
try {
// 获取新的token
const refreshSuccess = await getApptoken()
if (!refreshSuccess) {
return Promise.reject(new Error('获取新的token失败'))
}
// 重试原请求
const retryResponse = await request({
...config,
retryCount: config.retryCount + 1
})
// 执行队列中所有挂起的请求
requestsQueue.forEach(callback => callback())
requestsQueue = []
return retryResponse
} catch (refreshError) {
console.error('刷新token出错', refreshError)
uni.showToast({
title: '认证失败,请重新登录',
icon: 'none'
})
return Promise.reject(refreshError)
} finally {
isRefreshing = false // 重置刷新状态
}
}
// 其他错误处理
return Promise.reject(new Error(`请求失败,状态码:${statusCode}`))
}
// 封装常用请求方法
export const requestPost = (url, data, config = {}) => {
return request({
url,
data,
method: 'POST',
...config
})
}
export const requestGet = (url, config = {}) => {
return request({
url,
method: 'GET',
...config
})
}
javascript
复制代码
// tokenRequest.js
// 应用配置
const infoObj = {
appkey: process.env.ENV_TYPE === 'prod' ? 'C1A1140xxxxxxxxxxxxxxxxxxxxxxxxxxxx' :
'3232313xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
appSecret: process.env.ENV_TYPE === 'prod' ? '34D7C4Exxxxxxxxxxxxxxxxxxxxxxxxxxxx' :
'0A779D4xxxxxxxxxxxxxxxxxxxxxxxxxxxx',
token: ''
}
const baseURL = 'https://your-api.com'
// 基础请求(无拦截器)
const baseRequest = config => {
return new Promise((resolve, reject) => {
uni.request({
method: 'GET',
header: { 'Content-Type': 'application/json' },
dataType: 'json',
...config,
success: response => resolve(response.data), // 直接返回data
fail: error => reject(error)
})
})
}
// 获取AppToken
export const getApptoken = () => {
return new Promise((resolve, reject) => {
const oldtoken = getStoredApptoken()
const tokenUrl = `${baseURL}/getToken?token=${oldtoken}`
baseRequest({ url: tokenUrl })
.then(res => {
if (res.token) {
infoObj.token = res.token
uni.setStorageSync('infoObj', JSON.stringify(infoObj))
resolve(true)
} else {
uni.showToast({
title: '更新token出错',
icon: 'none'
})
resolve(false)
}
})
.catch(err => {
console.error('获取token接口失败', err)
uni.showToast({
title: '更新token接口出错',
icon: 'none'
})
resolve(false)
})
})
}
// 获取存储的AppToken
export const getStoredApptoken = () => {
try {
const stored = uni.getStorageSync('infoObj')
return stored ? JSON.parse(stored).token : ''
} catch (error) {
console.error('获取存储的token失败', error)
return ''
}
}
javascript
复制代码
// 示例:调用POST接口(如需发送数据)
const submitData = async () => {
try {
const params = { name: 'test', age: 20 };
// 调用POST接口(自动拼接token到URL)
const res = await requestPost('/api/submit', params);
console.log('提交成功', res);
} catch (err) {
console.error('提交失败', err);
}
};