import axios from 'axios'
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios'
import Cookies from 'js-cookie'
import { useMessage } from '@/hooks/useMessage'
const message = useMessage()
// 创建 axios 实例
const service: AxiosInstance = axios.create({
// API 的 base_url
baseURL: import.meta.env.VITE_API_BASE_URL || '/api',
// 请求超时时间
timeout: Number(import.meta.env.VITE_APP_API_TIMEOUT) || 15000,
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
})
// 请求队列管理
const pendingRequests = new Map()
const cancelToken = axios.CancelToken.source()
// 超时配置
const TIMEOUT_CONFIG = {
default: 15000,
upload: 30000,
download: 60000
}
// 生成请求的唯一键
const generateRequestKey = (config: InternalAxiosRequestConfig) => {
const { url, method, params, data } = config
return [url, method, JSON.stringify(params), JSON.stringify(data)].join('&')
}
// 添加请求到队列
const addPendingRequest = (config: InternalAxiosRequestConfig) => {
const requestKey = generateRequestKey(config)
if (!pendingRequests.has(requestKey)) {
config.cancelToken = cancelToken.token
pendingRequests.set(requestKey, config)
}
}
// 从队列中移除请求
const removePendingRequest = (config: InternalAxiosRequestConfig) => {
const requestKey = generateRequestKey(config)
pendingRequests.delete(requestKey)
}
// 清空所有请求
const clearPendingRequests = () => {
pendingRequests.forEach((config) => {
if (config.cancelToken) {
config.cancelToken.cancel('请求被取消')
}
})
pendingRequests.clear()
}
// XSS 过滤
const xssFilter = (data: any): any => {
if (typeof data === 'string') {
return data.replace(/[<>]/g, '')
}
if (Array.isArray(data)) {
return data.map(item => xssFilter(item))
}
if (typeof data === 'object' && data !== null) {
const result: any = {}
for (const key in data) {
result[key] = xssFilter(data[key])
}
return result
}
return data
}
// 请求拦截器
service.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// 从 Cookie 中获取 token
const token = Cookies.get('access_token')
if (token) {
config.headers.Authorization = `${token}`
}
// 添加 CSRF Token
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content')
if (csrfToken) {
config.headers['X-CSRF-Token'] = csrfToken
}
// 添加请求到队列
addPendingRequest(config)
// 设置超时时间
if (config.url?.includes('upload')) {
config.timeout = TIMEOUT_CONFIG.upload
} else if (config.url?.includes('download')) {
config.timeout = TIMEOUT_CONFIG.download
} else {
config.timeout = TIMEOUT_CONFIG.default
}
return config
},
(error) => {
message.error(error)
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
(response: AxiosResponse) => {
// 从队列中移除请求
removePendingRequest(response.config)
const res = response.data
// 这里可以根据后端返回的状态码做相应的处理
if (res.code === 200 || res.code === 0) {
// XSS 过滤
return xssFilter(res)
} else {
message.error(res.message || '请求失败')
return Promise.reject(new Error(res.message || '请求失败'))
}
},
(error) => {
// 从队列中移除请求
if (error.config) {
removePendingRequest(error.config)
}
message.error(error.message || '网络错误')
return Promise.reject(error)
}
)
// 封装 GET 请求
export function get<T>(url: string, params?: any): Promise<T> {
return service.get(url, { params })
}
// 封装 POST 请求
export function post<T>(url: string, data?: any): Promise<T> {
return service.post(url, data)
}
// 封装 PUT 请求
export function put<T>(url: string, data?: any): Promise<T> {
return service.put(url, data)
}
// 封装 DELETE 请求
export function del<T>(url: string): Promise<T> {
return service.delete(url)
}
export default service
调用:
import { get, post, put, del } from '@/utils/request'
interface ApiResponse<T> {
code: number
data: T
result: T
message: string
}
export const systemApi = {
// 获取服务器时间
getServerTime: () => {
return get<ApiResponse<number>>('自定义接口')
}
}
try {
const res = await systemApi.getServerTime()
// 将时间戳转换为 ISO 字符串
serverTime.value = new Date(res.result).toISOString()
} catch (error) {
console.error('获取服务器时间失败:', error)
}