uni-app 全局请求封装:支持 Promise,自动刷新 Token,解决 401 过期问题
在 uni-app
中封装一个全局通用的 ajax
请求函数,支持 Promise
,使用 uni.request()
进行请求,并且具备 自动刷新 token
的功能。以下是详细步骤:
实现步骤
- 创建
request.js
统一封装ajax
请求 - 管理
token
(存储、获取、刷新) - 处理
401
(登录过期)自动刷新token
- 防止
token
过期时多个请求同时触发refresh_token
- 错误处理和
Promise
封装
完整代码
创建 utils/request.js
作为 uni.request
的封装:
utils/request.js
// 导入 uni-app 的 storage API
const BASE_URL = 'https://api.example.com'; // 你的后端接口地址
let isRefreshing = false; // 是否正在刷新 token
let refreshSubscribers = []; // 存储刷新 token 期间的请求
/**
* 刷新 token 并返回新的 token
*/
function refreshToken() {
if (isRefreshing) {
// 如果已经在刷新 token,则返回一个等待的 Promise
return new Promise((resolve) => {
refreshSubscribers.push(resolve);
});
}
isRefreshing = true;
return new Promise((resolve, reject) => {
uni.request({
url: `${BASE_URL}/auth/refresh`, // 刷新 token 的 API
method: 'POST',
header: {
'Authorization': `Bearer ${uni.getStorageSync('refreshToken')}` // 发送 refreshToken
},
success: (res) => {
if (res.data.code === 200) {
const newToken = res.data.data.token;
const newRefreshToken = res.data.data.refreshToken;
// 存储新的 token 和 refreshToken
uni.setStorageSync('token', newToken);
uni.setStorageSync('refreshToken', newRefreshToken);
// 让所有等待的请求继续
refreshSubscribers.forEach((callback) => callback(newToken));
refreshSubscribers = [];
resolve(newToken);
} else {
reject('Refresh Token Failed');
}
},
fail: (err) => reject(err),
complete: () => {
isRefreshing = false;
}
});
});
}
/**
* 统一请求封装
* @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.auth=true] 是否需要携带 token
*/
function request({ url, method = 'GET', data = {}, header = {}, auth = true }) {
return new Promise((resolve, reject) => {
// 获取存储的 token
let token = uni.getStorageSync('token');
// 组装请求头
let finalHeader = {
'Content-Type': 'application/json',
...header
};
if (auth && token) {
finalHeader['Authorization'] = `Bearer ${token}`;
}
uni.request({
url: `${BASE_URL}${url}`,
method,
data,
header: finalHeader,
success: async (res) => {
if (res.statusCode === 200) {
resolve(res.data);
} else if (res.statusCode === 401 && auth) {
// token 失效,自动刷新 token
try {
const newToken = await refreshToken();
finalHeader['Authorization'] = `Bearer ${newToken}`;
// 重新发起请求
uni.request({
url: `${BASE_URL}${url}`,
method,
data,
header: finalHeader,
success: (retryRes) => resolve(retryRes.data),
fail: (retryErr) => reject(retryErr)
});
} catch (error) {
reject('登录状态失效,请重新登录');
uni.removeStorageSync('token');
uni.removeStorageSync('refreshToken');
uni.reLaunch({ url: '/pages/login/login' });
}
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
}
});
});
}
export default request;
使用方式
在 pages/index/index.vue
页面调用封装的 request.js
:
import request from '../../utils/request.js';
request({
url: '/user/info',
method: 'GET'
}).then(res => {
console.log('用户信息:', res);
}).catch(err => {
console.error('请求失败:', err);
});
核心功能解读
- 支持
Promise
,简化then/catch
处理 - 全局
request
统一封装,避免每个请求都写uni.request
- 自动携带
token
,401 过期自动刷新 - 防止多个请求同时触发
refreshToken
,队列处理 - 若
refresh_token
失效,清除token
并跳转到login
页面
优化建议
- 错误信息细化:根据后端
code
细分错误(如403
、500
)。 - 可配置
BASE_URL
:放到config.js
,区分dev
和prod
环境。 - 超时处理:可加
setTimeout
限制请求时间。
这样,uni-app
就具备了全局 ajax
请求封装,且能自动刷新 token
,提升开发效率! 🚀