video-flow-b/api/request.ts
2025-07-01 18:12:59 +08:00

175 lines
4.6 KiB
TypeScript

import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, AxiosHeaders } from 'axios';
import { BASE_URL } from './constants'
// 创建 axios 实例
const request: AxiosInstance = axios.create({
baseURL: BASE_URL, // 设置基础URL
timeout: 300000, // 请求超时时间
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
request.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// 从 localStorage 获取 token
const token = localStorage.getItem('token') || 'mock-token';
if (token && config.headers) {
(config.headers as AxiosHeaders).set('Authorization', `Bearer ${token}`);
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response: AxiosResponse) => {
// 直接返回响应数据
return response.data;
},
(error) => {
if (error.response) {
switch (error.response.status) {
case 401:
// 未授权,清除 token 并跳转到登录页
localStorage.removeItem('token');
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.message || '未知错误');
}
} else if (error.request) {
// 请求已发出但没有收到响应
console.error('网络错误,请检查您的网络连接');
} else {
// 请求配置出错
console.error('请求配置错误:', error.message);
}
return Promise.reject(error);
}
);
// 封装 GET 请求
export const get = <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.get(url, config);
};
// 封装 POST 请求
export const post = <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.post(url, data, config);
};
// 封装 PUT 请求
export const put = <T>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> => {
return request.put(url, data, config);
};
// 封装 DELETE 请求
export const del = <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
return request.delete(url, config);
};
// 封装流式数据请求
export const stream = async <T>({
url,
method = 'POST',
data,
onMessage,
onError,
onComplete,
}: {
url: string;
method?: 'GET' | 'POST';
data?: any;
onMessage: (data: T) => void;
onError?: (error: any) => void;
onComplete?: () => void;
}) => {
try {
const config: AxiosRequestConfig = {
url,
method,
data,
responseType: 'stream',
headers: {
'Accept': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
},
onDownloadProgress: (progressEvent: any) => {
const responseText = progressEvent.event?.target?.responseText;
if (!responseText) return;
// 处理接收到的数据
const lines: string[] = responseText.split('\n');
lines.forEach((line: string) => {
if (line.startsWith('data: ')) {
try {
const data = JSON.parse(line.slice(6));
onMessage(data);
} catch (e) {
console.warn('Failed to parse stream data:', e);
}
}
});
},
};
const response = await request(config);
onComplete?.();
return response;
} catch (error) {
onError?.(error);
throw error;
}
};
// 封装文件下载流请求
export const downloadStream = async (
url: string,
filename: string,
config?: AxiosRequestConfig
) => {
try {
const response = await request({
url,
method: 'GET',
responseType: 'blob',
...config,
});
// 创建下载链接
const blob = new Blob([response.data], { type: response.headers['content-type'] });
const downloadUrl = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
window.URL.revokeObjectURL(downloadUrl);
return response;
} catch (error) {
console.error('文件下载失败:', error);
throw error;
}
};
// 导出 request 实例
export default request;