|
@@ -1,132 +1,66 @@
|
|
|
-import axios, {
|
|
|
- AxiosInstance,
|
|
|
- AxiosRequestConfig,
|
|
|
- AxiosResponse,
|
|
|
- Canceler,
|
|
|
- AxiosError
|
|
|
-} from 'axios';
|
|
|
+import axios from "axios";
|
|
|
+import { ElMessage } from "element-plus"; // 你也可以换成自己的提示组件
|
|
|
+import router from "@/router"; // 如果需要跳转登录页
|
|
|
+import type { CommonReqResponseData } from '../types/index';
|
|
|
|
|
|
-type RequestInterceptor = (
|
|
|
- config: AxiosRequestConfig
|
|
|
-) => AxiosRequestConfig | Promise<AxiosRequestConfig>;
|
|
|
-type ResponseInterceptor = (response: AxiosResponse) => AxiosResponse | Promise<AxiosResponse>;
|
|
|
+// 创建 axios 实例
|
|
|
+const http = axios.create({
|
|
|
+ baseURL: import.meta.env.VITE_BASE_API || "/api", // 根据环境变量配置
|
|
|
+ timeout: 60000, // 超时时间
|
|
|
+});
|
|
|
|
|
|
-interface AxiosInterceptorOptions {
|
|
|
- requestInterceptors?: RequestInterceptor[];
|
|
|
- responseInterceptors?: ResponseInterceptor[];
|
|
|
-}
|
|
|
-
|
|
|
-class AxiosHttp {
|
|
|
- private axiosInstance: AxiosInstance;
|
|
|
- private cancelMap = new Map<string, Canceler>();
|
|
|
-
|
|
|
- constructor(config?: AxiosRequestConfig, options?: AxiosInterceptorOptions) {
|
|
|
- this.axiosInstance = axios.create(config);
|
|
|
-
|
|
|
- // 添加请求拦截器
|
|
|
- options?.requestInterceptors?.forEach((interceptor) => {
|
|
|
- this.axiosInstance.interceptors.request.use(
|
|
|
- async (config: any) => {
|
|
|
- config = await interceptor(config);
|
|
|
- return config;
|
|
|
- },
|
|
|
- (error: AxiosError) => Promise.reject(error)
|
|
|
- );
|
|
|
- });
|
|
|
-
|
|
|
- // 添加响应拦截器
|
|
|
- options?.responseInterceptors?.forEach((interceptor) => {
|
|
|
- this.axiosInstance.interceptors.response.use(
|
|
|
- async (response: AxiosResponse) => {
|
|
|
- response = await interceptor(response);
|
|
|
- return response;
|
|
|
- },
|
|
|
- (error: AxiosError) => Promise.reject(error)
|
|
|
- );
|
|
|
- });
|
|
|
-
|
|
|
- // 统一请求拦截 - 生成取消Token
|
|
|
- this.axiosInstance.interceptors.request.use((config) => {
|
|
|
- const requestKey = this.getRequestKey(config);
|
|
|
- if (this.cancelMap.has(requestKey)) {
|
|
|
- // 取消重复请求
|
|
|
- const cancel = this.cancelMap.get(requestKey);
|
|
|
- cancel?.(`取消重复请求: ${requestKey}`);
|
|
|
- this.cancelMap.delete(requestKey);
|
|
|
- }
|
|
|
- config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
|
|
|
- this.cancelMap.set(requestKey, cancel);
|
|
|
- });
|
|
|
- return config;
|
|
|
- });
|
|
|
-
|
|
|
- // 请求完成后清除取消函数
|
|
|
- this.axiosInstance.interceptors.response.use(
|
|
|
- (response: AxiosResponse) => {
|
|
|
- const requestKey = this.getRequestKey(response.config);
|
|
|
- this.cancelMap.delete(requestKey);
|
|
|
- return response;
|
|
|
- },
|
|
|
- (error: AxiosError) => {
|
|
|
- if (axios.isCancel(error)) {
|
|
|
- console.warn(error.message);
|
|
|
- }
|
|
|
- if (error.config) {
|
|
|
- const requestKey = this.getRequestKey(error.config);
|
|
|
- this.cancelMap.delete(requestKey);
|
|
|
- }
|
|
|
- return Promise.reject(error);
|
|
|
- }
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- private getRequestKey(config: AxiosRequestConfig): string {
|
|
|
- const url = config.url || '';
|
|
|
- const method = config.method || 'get';
|
|
|
- const params = config.params ? JSON.stringify(config.params) : '';
|
|
|
- const data = config.data ? JSON.stringify(config.data) : '';
|
|
|
- return [method, url, params, data].join('&');
|
|
|
+// 请求拦截器
|
|
|
+http.interceptors.request.use(
|
|
|
+ (config) => {
|
|
|
+ // 这里可以统一加 token
|
|
|
+ const token = localStorage.getItem("token");
|
|
|
+ if (token) {
|
|
|
+ config.headers.Authorization = `Bearer ${token}`;
|
|
|
+ }
|
|
|
+ return config;
|
|
|
+ },
|
|
|
+ (error) => {
|
|
|
+ return Promise.reject(error);
|
|
|
}
|
|
|
+);
|
|
|
|
|
|
- request<T = any>(config: AxiosRequestConfig): Promise<T> {
|
|
|
- return this.axiosInstance.request<T>(config).then((res: AxiosResponse) => res.data);
|
|
|
- }
|
|
|
-
|
|
|
- get<T = any>(url: string, config?: AxiosRequestConfig): Promise<T> {
|
|
|
- return this.request<T>({ ...config, method: 'get', url });
|
|
|
- }
|
|
|
-
|
|
|
- post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
|
|
|
- return this.request<T>({ ...config, method: 'post', url, data });
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-export const request = new AxiosHttp(
|
|
|
- { baseURL: '/api', timeout: 5000 },
|
|
|
- {
|
|
|
- requestInterceptors: [
|
|
|
- (config) => {
|
|
|
- config.headers = config.headers || {};
|
|
|
- config.headers.Authorization = 'Bearer token';
|
|
|
- return config;
|
|
|
+// 响应拦截器
|
|
|
+http.interceptors.response.use(
|
|
|
+ (response: any) => {
|
|
|
+ console.log(response, '-=-=-')
|
|
|
+ const state = response.state;
|
|
|
+ // 你可以根据后端约定的 code 来处理
|
|
|
+ if (state !== 200) {
|
|
|
+ ElMessage.error(response.msg || "请求出错");
|
|
|
+ }
|
|
|
+ return response; // 正常返回数据
|
|
|
+ },
|
|
|
+ (error) => {
|
|
|
+ if (error.response) {
|
|
|
+ const status = error.response.status;
|
|
|
+ switch (status) {
|
|
|
+ case 401:
|
|
|
+ ElMessage.error("登录已过期,请重新登录");
|
|
|
+ localStorage.removeItem("token");
|
|
|
+ router.push("/login");
|
|
|
+ break;
|
|
|
+ case 403:
|
|
|
+ ElMessage.error("没有权限");
|
|
|
+ break;
|
|
|
+ case 404:
|
|
|
+ ElMessage.error("接口不存在");
|
|
|
+ break;
|
|
|
+ case 500:
|
|
|
+ ElMessage.error("服务器错误");
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ ElMessage.error(error.message);
|
|
|
}
|
|
|
- ],
|
|
|
- responseInterceptors: [
|
|
|
- (response) => {
|
|
|
- if (response.status !== 200) {
|
|
|
- throw new Error('请求失败');
|
|
|
- }
|
|
|
- return response;
|
|
|
- }
|
|
|
- ]
|
|
|
+ } else {
|
|
|
+ ElMessage.error("网络错误");
|
|
|
+ }
|
|
|
+ return Promise.reject(error);
|
|
|
}
|
|
|
);
|
|
|
|
|
|
-// api
|
|
|
-// .get('/users')
|
|
|
-// .then((data) => console.log(data))
|
|
|
-// .catch((err) => console.error(err.message));
|
|
|
-
|
|
|
-// // 同时重复请求会取消前一个请求
|
|
|
-// api.get('/users');
|
|
|
-// api.get('/users'); // 这会取消上一个
|
|
|
+export default http;
|