You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.1 KiB
TypeScript
123 lines
3.1 KiB
TypeScript
|
1 month ago
|
// utils/apiClient.ts
|
||
|
|
import { ofetch } from 'ofetch'
|
||
|
|
import { CookieManager } from './cookieManager'
|
||
|
|
import { STORAGE_KEYS } from '~/utils/storageKeys';
|
||
|
|
import { AuthService } from '~/services/authService';
|
||
|
|
|
||
|
|
// 创建API客户端实例
|
||
|
|
class ApiClient {
|
||
|
|
private baseUrl: string = '/api' // 默认值
|
||
|
|
|
||
|
|
// 设置基础URL的公共方法
|
||
|
|
setBaseUrl() {
|
||
|
|
const config = useRuntimeConfig();
|
||
|
|
this.baseUrl = config.public.apiBaseUrl || '/api';
|
||
|
|
}
|
||
|
|
|
||
|
|
private buildUrl(url: string): string {
|
||
|
|
this.setBaseUrl();
|
||
|
|
const basePath = this.baseUrl.replace(/\/$/, '')
|
||
|
|
const apiPath = url.startsWith('/') ? url : '/' + url
|
||
|
|
return basePath + apiPath
|
||
|
|
}
|
||
|
|
|
||
|
|
// 通用请求方法
|
||
|
|
private async request<T>(
|
||
|
|
url: string,
|
||
|
|
options: any = {}
|
||
|
|
): Promise<T> {
|
||
|
|
const fullUrl = this.buildUrl(url)
|
||
|
|
// AuthService.getAuthToken();
|
||
|
|
// 自动添加认证头
|
||
|
|
let token = AuthService.getAuthToken();
|
||
|
|
if (import.meta.client && !token) {
|
||
|
|
token = localStorage.getItem(STORAGE_KEYS.GLOBAL_TOKEN);
|
||
|
|
}
|
||
|
|
// CookieManager.get(STORAGE_KEYS.GLOBAL_TOKEN)
|
||
|
|
|
||
|
|
console.log('API Request:', fullUrl, options, token)
|
||
|
|
if (token && !options.headers?.Authorization) {
|
||
|
|
options.headers = {
|
||
|
|
...options.headers,
|
||
|
|
Authorization: `Bearer ${token}`
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
const response = await ofetch<T>(fullUrl, {
|
||
|
|
...options,
|
||
|
|
// 默认配置
|
||
|
|
retry: 0, // 开发环境不重试
|
||
|
|
timeout: 30000, // 30秒超时
|
||
|
|
onResponse({ response }) {
|
||
|
|
// 响应拦截器
|
||
|
|
// if (response.status === 401) {
|
||
|
|
// console.warn('Authentication required')
|
||
|
|
// }
|
||
|
|
},
|
||
|
|
onResponseError({ response }) {
|
||
|
|
// 响应错误拦截器
|
||
|
|
console.error(`API Error: ${fullUrl} -- ${response}`)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
return response
|
||
|
|
} catch (error: any) {
|
||
|
|
// 统一错误处理
|
||
|
|
if (error.name === 'FetchError') {
|
||
|
|
throw new Error(`网络请求失败: ${error.message}`)
|
||
|
|
}
|
||
|
|
throw error
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// GET请求
|
||
|
|
async get<T>(url: string, options: any = {}): Promise<T> {
|
||
|
|
return this.request<T>(url, {
|
||
|
|
...options,
|
||
|
|
method: 'GET'
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// POST请求
|
||
|
|
async post<T>(url: string, data?: any, options: any = {}): Promise<T> {
|
||
|
|
return this.request<T>(url, {
|
||
|
|
...options,
|
||
|
|
method: 'POST',
|
||
|
|
body: data
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// PUT请求
|
||
|
|
async put<T>(url: string, data?: any, options: any = {}): Promise<T> {
|
||
|
|
return this.request<T>(url, {
|
||
|
|
...options,
|
||
|
|
method: 'PUT',
|
||
|
|
body: data
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// DELETE请求
|
||
|
|
async delete<T>(url: string, data?: any, options: any = {}): Promise<T> {
|
||
|
|
return this.request<T>(url, {
|
||
|
|
...options,
|
||
|
|
method: 'DELETE',
|
||
|
|
body: data
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// PATCH请求
|
||
|
|
async patch<T>(url: string, data?: any, options: any = {}): Promise<T> {
|
||
|
|
return this.request<T>(url, {
|
||
|
|
...options,
|
||
|
|
method: 'PATCH',
|
||
|
|
body: data
|
||
|
|
})
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 导出单例实例
|
||
|
|
export const apiClient = new ApiClient()
|
||
|
|
|
||
|
|
// 也可以导出ofetch实例供直接使用
|
||
|
|
export { ofetch }
|