129 lines
3.6 KiB
TypeScript
129 lines
3.6 KiB
TypeScript
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
|
||
|
||
// 创建 axios 实例
|
||
const instance: AxiosInstance = axios.create({
|
||
baseURL: '/api', // 通过 Vite 代理转发到 Go 后端
|
||
timeout: 300000, // 5分钟超时(300秒),适应AI评分长时间处理
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
})
|
||
|
||
// 请求拦截器
|
||
instance.interceptors.request.use(
|
||
(config) => {
|
||
// 可以在这里添加 token 等认证信息
|
||
const token = localStorage.getItem('token')
|
||
if (token && config.headers) {
|
||
config.headers.Authorization = `Bearer ${token}`
|
||
}
|
||
return config
|
||
},
|
||
(error) => {
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
// 响应拦截器
|
||
instance.interceptors.response.use(
|
||
(response: AxiosResponse) => {
|
||
return response.data
|
||
},
|
||
(error) => {
|
||
// 统一错误处理
|
||
if (error.response) {
|
||
switch (error.response.status) {
|
||
case 401:
|
||
// 未授权,清除本地存储并跳转到登录页
|
||
console.error('Token已过期或未授权,请重新登录')
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('user')
|
||
// 跳转到登录页
|
||
window.location.href = '/login'
|
||
break
|
||
case 403:
|
||
console.error('没有权限访问')
|
||
break
|
||
case 404:
|
||
console.error('请求的资源不存在')
|
||
break
|
||
case 500:
|
||
console.error('服务器错误')
|
||
break
|
||
default:
|
||
console.error('请求失败:', error.response.data)
|
||
}
|
||
} else {
|
||
console.error('网络错误:', error.message)
|
||
}
|
||
return Promise.reject(error)
|
||
}
|
||
)
|
||
|
||
// 封装请求方法
|
||
export const request = {
|
||
get: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.get(url, config)
|
||
},
|
||
post: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.post(url, data, config)
|
||
},
|
||
put: <T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.put(url, data, config)
|
||
},
|
||
delete: <T = any>(url: string, config?: AxiosRequestConfig): Promise<T> => {
|
||
return instance.delete(url, config)
|
||
},
|
||
}
|
||
|
||
// 统一的 fetch 请求工具(用于需要原生 fetch 的场景,如流式请求)
|
||
interface FetchOptions extends RequestInit {
|
||
// 扩展选项(如果需要)
|
||
}
|
||
|
||
/**
|
||
* 统一封装的 fetch 请求方法
|
||
* 自动添加 Authorization header 和其他通用配置
|
||
*/
|
||
export const fetchWithAuth = async (
|
||
url: string,
|
||
options: FetchOptions = {}
|
||
): Promise<Response> => {
|
||
// 获取 token
|
||
const token = localStorage.getItem('token')
|
||
|
||
// 合并 headers
|
||
const headers: Record<string, string> = {
|
||
'Content-Type': 'application/json',
|
||
...(options.headers as Record<string, string>),
|
||
}
|
||
|
||
// 如果有 token,添加到请求头
|
||
if (token) {
|
||
headers['Authorization'] = `Bearer ${token}`
|
||
}
|
||
|
||
// 构建完整的请求配置
|
||
const fetchOptions: RequestInit = {
|
||
...options,
|
||
headers,
|
||
}
|
||
|
||
// 发送请求
|
||
const response = await fetch(url, fetchOptions)
|
||
|
||
// 统一处理 401 未授权错误
|
||
// 注意:如果已经在登录页面,不要跳转,让登录页面自己处理错误提示
|
||
if (response.status === 401 && !window.location.pathname.startsWith('/login')) {
|
||
console.error('Token已过期或未授权,请重新登录')
|
||
localStorage.removeItem('token')
|
||
localStorage.removeItem('user')
|
||
window.location.href = '/login'
|
||
throw new Error('未授权,请重新登录')
|
||
}
|
||
|
||
return response
|
||
}
|
||
|
||
export default instance
|