From 952f7fc00a59f144afee7685fdb3be530fddca81 Mon Sep 17 00:00:00 2001 From: chenweiqiang Date: Wed, 30 Apr 2025 10:22:59 +0800 Subject: [PATCH] modify --- src/utils/auth.js | 88 +++++++++++++++++++++++++++++++++++++++++++++++ src/utils/http.js | 6 ++-- 2 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 src/utils/auth.js diff --git a/src/utils/auth.js b/src/utils/auth.js new file mode 100644 index 0000000..2c8ed70 --- /dev/null +++ b/src/utils/auth.js @@ -0,0 +1,88 @@ +let isRefreshing = false // 刷新状态锁 +let requestsQueue = [] // 等待队列 + +// 核心拦截器 +export const authInterceptor = async (config) => { + // 1. 获取当前 Token + let token = uni.getStorageSync('token') + const refreshToken = uni.getStorageSync('refreshToken') + + // 2. 检查是否需要跳过认证 + if (config.skipAuth) return config + + // 3. 自动添加 Authorization 头 + if (token) { + config.header = { + ...config.header, + Authorization: `Bearer ${token}` + } + } + + // 4. 小程序 HTTPS 强制转换 + // #ifdef MP-WEIXIN + if (config.url.startsWith('http:')) { + config.url = config.url.replace('http:', 'https:') + } + // #endif + + return config +} + +// 刷新 Token 逻辑 +const refreshTokenRequest = async () => { + try { + const { data } = await uni.request({ + url: '/auth/refresh', + method: 'POST', + data: { + refresh_token: uni.getStorageSync('refreshToken') + } + }) + + // 更新存储 + uni.setStorageSync('token', data.token) + uni.setStorageSync('refreshToken', data.refreshToken) + return data.token + } catch (error) { + // 刷新失败跳转登录 + uni.removeStorageSync('token') + uni.removeStorageSync('refreshToken') + uni.reLaunch({ url: '/pages/login/login' }) + throw new Error('登录已过期,请重新登录') + } +} + +// 响应拦截器处理 Token 过期 +export const authErrorHandler = async (error) => { + const { statusCode, config } = error + + // 1. 非 401 错误直接抛出 + if (statusCode !== 401 || config.skipAuth) throw error + + // 2. 正在刷新时缓存请求 + if (isRefreshing) { + return new Promise((resolve) => { + requestsQueue.push(() => resolve(http.request(config))) + }) + } + + // 3. 标记刷新状态 + isRefreshing = true + + try { + // 4. 执行 Token 刷新 + const newToken = await refreshTokenRequest() + + // 5. 更新原请求头 + config.header.Authorization = `Bearer ${newToken}` + + // 6. 重试所有等待请求 + requestsQueue.forEach(cb => cb()) + requestsQueue = [] + + // 7. 重试当前请求 + return http.request(config) + } finally { + isRefreshing = false + } +} \ No newline at end of file diff --git a/src/utils/http.js b/src/utils/http.js index d4da118..a6cd012 100644 --- a/src/utils/http.js +++ b/src/utils/http.js @@ -1,3 +1,5 @@ +import { authInterceptor, authErrorHandler } from './auth' + class Request { constructor() { // 全局默认配置 @@ -16,8 +18,8 @@ class Request { // 拦截器存储 this.interceptors = { - request: [], - response: [] + request: [authInterceptor], + response: [authErrorHandler] } // 请求队列(用于取消请求)