更新
This commit is contained in:
145
src/utils/request.js
Normal file
145
src/utils/request.js
Normal file
@@ -0,0 +1,145 @@
|
||||
import axios from 'axios'
|
||||
import config from '@/config'
|
||||
import { useUserStore } from '@/stores/modules/user'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import router from '@/router'
|
||||
|
||||
const http = axios.create({
|
||||
timeout: 30000,
|
||||
baseURL: config.baseURL
|
||||
})
|
||||
|
||||
// 是否正在刷新 token
|
||||
let isRefreshing = false
|
||||
// 存储待重试的请求
|
||||
let requests = []
|
||||
|
||||
// 请求拦截器
|
||||
http.interceptors.request.use(
|
||||
(config) => {
|
||||
const userStore = useUserStore()
|
||||
const token = userStore.token
|
||||
|
||||
// 如果有 token,添加到请求头
|
||||
if (token) {
|
||||
config.headers['Authorization'] = `Bearer ${token}`
|
||||
}
|
||||
|
||||
return config
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 响应拦截器
|
||||
http.interceptors.response.use(
|
||||
(response) => {
|
||||
// 根据后端返回的数据结构进行处理
|
||||
// 假设后端返回格式为 { code, data, message }
|
||||
const { code, data, message } = response.data
|
||||
|
||||
// 请求成功
|
||||
if (code === 200 || code === 0) {
|
||||
return data
|
||||
}
|
||||
|
||||
// 其他错误码处理
|
||||
ElMessage.error(message || '请求失败')
|
||||
return Promise.reject(new Error(message || '请求失败'))
|
||||
},
|
||||
async (error) => {
|
||||
const userStore = useUserStore()
|
||||
const { response } = error
|
||||
|
||||
// 无响应(网络错误、超时等)
|
||||
if (!response) {
|
||||
ElMessage.error('网络错误,请检查网络连接')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
const { status, data } = response
|
||||
|
||||
// 401 未授权 - token 过期或无效
|
||||
if (status === 401) {
|
||||
// 如果正在刷新 token,将请求加入队列
|
||||
if (isRefreshing) {
|
||||
return new Promise((resolve) => {
|
||||
requests.push((token) => {
|
||||
// 重新设置请求头
|
||||
error.config.headers['Authorization'] = `Bearer ${token}`
|
||||
resolve(http(error.config))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 标记正在刷新
|
||||
isRefreshing = true
|
||||
|
||||
try {
|
||||
// 尝试刷新 token
|
||||
const newToken = await refreshToken()
|
||||
|
||||
// 刷新成功,更新 token
|
||||
userStore.setToken(newToken)
|
||||
|
||||
// 执行队列中的所有请求
|
||||
requests.forEach((callback) => callback(newToken))
|
||||
requests = []
|
||||
|
||||
// 重新执行当前请求
|
||||
error.config.headers['Authorization'] = `Bearer ${newToken}`
|
||||
return http(error.config)
|
||||
} catch (refreshError) {
|
||||
// 刷新失败,清空队列并跳转登录页
|
||||
requests = []
|
||||
userStore.logout()
|
||||
router.push('/login')
|
||||
ElMessage.error('登录已过期,请重新登录')
|
||||
return Promise.reject(refreshError)
|
||||
} finally {
|
||||
isRefreshing = false
|
||||
}
|
||||
}
|
||||
|
||||
// 403 禁止访问
|
||||
if (status === 403) {
|
||||
ElMessage.error('没有权限访问该资源')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
// 404 资源不存在
|
||||
if (status === 404) {
|
||||
ElMessage.error('请求的资源不存在')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
// 500 服务器错误
|
||||
if (status >= 500) {
|
||||
ElMessage.error('服务器错误,请稍后重试')
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
// 其他错误
|
||||
const errorMessage = data?.message || error.message || '请求失败'
|
||||
ElMessage.error(errorMessage)
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
// 刷新 token 的方法
|
||||
async function refreshToken() {
|
||||
// 这里需要根据实际的刷新 token 接口进行修改
|
||||
// 假设刷新接口是 /auth/refresh
|
||||
const refreshUrl = config.baseURL + '/auth/refresh'
|
||||
const refreshTokenValue = localStorage.getItem('refreshToken')
|
||||
|
||||
const response = await axios.post(refreshUrl, {
|
||||
refreshToken: refreshTokenValue
|
||||
})
|
||||
|
||||
// 假设返回格式为 { code, data: { token, refreshToken } }
|
||||
return response.data.data.token
|
||||
}
|
||||
|
||||
export default http
|
||||
Reference in New Issue
Block a user