当前位置: 首页 > news >正文

uni-app 全局请求封装:支持 Promise,自动刷新 Token,解决 401 过期问题

uni-app 中封装一个全局通用的 ajax 请求函数,支持 Promise,使用 uni.request() 进行请求,并且具备 自动刷新 token 的功能。以下是详细步骤:


实现步骤

  1. 创建 request.js 统一封装 ajax 请求
  2. 管理 token(存储、获取、刷新)
  3. 处理 401(登录过期)自动刷新 token
  4. 防止 token 过期时多个请求同时触发 refresh_token
  5. 错误处理和 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);
});

核心功能解读

  1. 支持 Promise,简化 then/catch 处理
  2. 全局 request 统一封装,避免每个请求都写 uni.request
  3. 自动携带 token,401 过期自动刷新
  4. 防止多个请求同时触发 refreshToken,队列处理
  5. refresh_token 失效,清除 token 并跳转到 login 页面

优化建议

  • 错误信息细化:根据后端 code 细分错误(如 403500)。
  • 可配置 BASE_URL:放到 config.js,区分 devprod 环境。
  • 超时处理:可加 setTimeout 限制请求时间。

这样,uni-app 就具备了全局 ajax 请求封装,且能自动刷新 token,提升开发效率! 🚀

相关文章:

  • 【框架】Spring、SpringBoot和SpringCloud区别
  • c++常用算法
  • 【Linux】消息队列和信号量
  • 深入理解Reactor Flux的生成方法
  • idea显示.java文件不能运行解决方式
  • Java 容器之 List
  • jenkens使用笔记
  • 探索Elasticsearch:认识与安装
  • 不谓侠--记录
  • Hive-08之数据仓库之建模、分析
  • 0111 AI淘金新时代:DeepSeek+工具矩阵的7大变现路径
  • 滞后补偿和超前补偿
  • ctfshow刷题笔记—栈溢出—pwn61~pwn64
  • 物联网小范围高精度GPS使用
  • 华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway
  • 利用@WebMvcTest测试Spring MVC应用
  • 线程 -- 线程池
  • 开学季大学生如何备考微软MOS认证?
  • 中间件专栏之Redis篇——Redis中过期key删除和内存淘汰策略
  • 动态规划/贪心算法
  • qq登录网站授权怎么做/网站维护是做什么的
  • 廊坊网站建设团队/seo快速优化软件网站
  • asp网站打不开/成都百度提升优化
  • 网站建设时送的ppt方案/北京seo优化厂家
  • 淘宝几百块钱做网站靠谱吗/西安关键词seo
  • 上海城隍庙在哪个区/系统优化软件哪个好