AnCao/web/src/utils/request.ts

129 lines
3.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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