虽然Nuxt3自带$fetch,但某些特定场景比如需要上传进度的文件上传功能需要用到axios

标准函数方法,可能不适用于nuxt

// utils/http.ts
import type {
    AxiosInstance,
    AxiosRequestConfig,
    AxiosResponse,
    InternalAxiosRequestConfig,
} from 'axios';
import axios from 'axios';

import { PageEnum } from '@/enums/pageEnum';
import { RequestCodeEnum } from '@/enums/requestEnum';

import { config } from '@/config'

interface ResponseType<T = any> {
    code: RequestCodeEnum;
    data: T;
    msg: string;
    show: 1 | 0;
}

// 创建 Axios 实例
const instance: AxiosInstance = axios.create({
    baseURL: `${config.apiBase}${config.apiPrefix}`,
    timeout: 10 * 60 * 1000, // 请求超时时间
});

// 请求拦截器
instance.interceptors.request.use(
    (config: InternalAxiosRequestConfig) => {
        // 在发送请求前可以在这里添加全局配置,比如添加 Token
        const userStore = useUserStore();
        const token = userStore.token;
        if (token) {
            config.headers.set('Token', token);
        }
        return config;
    },
    (error) => {
        // 请求错误处理
        return Promise.reject(error);
    }
);

// 响应拦截器
instance.interceptors.response.use(
    (response: AxiosResponse<ResponseType>) => {
        const showMessage = response.data.show;
        const message = response.data.msg;
        const userStore = useUserStore();
        const resultData = response.data.data;
        const codeMap = {
            [RequestCodeEnum.SUCCESS]: () => {
                isClient(() => {
                    if (showMessage === 1) {
                        useMessage().success(message);
                    }
                });
            },
            [RequestCodeEnum.FAIL]: () => {
                isClient(() => {
                    if (showMessage === 1) {
                        useMessage().error(message);
                    }
                });
                Promise.reject(message);
            },
            [RequestCodeEnum.LOGIN_FAILURE]: () => {
                isClient(() => {
                    userStore.logout(true);
                });
                Promise.reject(message);
            },
            [RequestCodeEnum.NOT_INSTALL]: () => {
                isClient(() => {
                    window.location.replace(PageEnum.INSTALL);
                });
            },
            [RequestCodeEnum.OPEN_NEW_PAGE]: () => {
                isClient(() => {
                    window.open(
                        typeof resultData === 'string' ? resultData : (resultData as any).url
                    );
                });
            },
        }[response.data.code];

        if (codeMap) {
            codeMap();
        } else {
            Promise.reject(message);
        }
        return response.data.data;
    },
    (error) => {
        return Promise.reject(error);
    }
);

// 封装通用请求方法
const useAxios = {
    get<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
        return instance.get(url, { params, ...config });
    },
    post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
        return instance.post(url, data, { ...config });
    },
    upload<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
        const formData = new FormData();
        if (data) {
            Object.keys(data).forEach((key) => {
                formData.append(key, data[key]);
            });
        }
        return instance.post(url, data, { ...config });
    },
};

export default useAxios;

Class版本,new的时候才产生实例,所以不影响Nuxt3使用

import type {
    AxiosInstance,
    AxiosRequestConfig,
    AxiosResponse,
    InternalAxiosRequestConfig,
} from 'axios';
import axios from 'axios';

import { PageEnum } from '~/enums/pageEnum';
import { RequestCodeEnum } from '~/enums/requestEnum';

interface ResponseType<T = any> {
    code: RequestCodeEnum;
    data: T;
    msg: string;
    show: 1 | 0;
}

export class AxiosService {
    private instance: AxiosInstance;

    constructor() {
        this.instance = axios.create({
            timeout: 10 * 60 * 1000,
        });

        this.setupInterceptors();
    }

    // 设置拦截器
    private setupInterceptors() {
        // 请求拦截器
        this.instance.interceptors.request.use(
            (config: InternalAxiosRequestConfig) => {
                const runtimeConfig = useRuntimeConfig();
                config.baseURL = `${runtimeConfig.public.apiBase}${runtimeConfig.public.apiPrefix}`;
                const userStore = useUserStore();
                const token = userStore.token;
                if (token) {
                    config.headers.set('Token', token);
                }
                return config;
            },
            (error) => {
                return Promise.reject(error);
            }
        );

        // 响应拦截器
        this.instance.interceptors.response.use(
            (response: AxiosResponse<ResponseType>) => {
                const showMessage = response.data.show;
                const message = response.data.msg;
                const userStore = useUserStore();
                const resultData = response.data.data;

                const codeMap = {
                    [RequestCodeEnum.SUCCESS]: () => {
                        isClient(() => {
                            if (showMessage === 1) {
                                useMessage().success(message);
                            }
                        });
                    },
                    [RequestCodeEnum.FAIL]: () => {
                        isClient(() => {
                            if (showMessage === 1) {
                                useMessage().error(message);
                            }
                        });
                        return Promise.reject(message);
                    },
                    [RequestCodeEnum.LOGIN_FAILURE]: () => {
                        isClient(() => {
                            userStore.logout(true);
                        });
                        return Promise.reject(message);
                    },
                    [RequestCodeEnum.NOT_INSTALL]: () => {
                        isClient(() => {
                            window.location.replace(PageEnum.INSTALL);
                        });
                    },
                    [RequestCodeEnum.OPEN_NEW_PAGE]: () => {
                        isClient(() => {
                            window.open(
                                typeof resultData === 'string'
                                    ? resultData
                                    : (resultData as any).url
                            );
                        });
                    },
                }[response.data.code];

                if (codeMap) {
                    codeMap();
                } else {
                    return Promise.reject(message);
                }
                return response.data.data;
            },
            (error) => {
                return Promise.reject(error);
            }
        );
    }

    // 通用 GET 请求
    public get<T = any>(url: string, params?: any, config?: AxiosRequestConfig): Promise<T> {
        return this.instance.get(url, { params, ...config });
    }

    // 通用 POST 请求
    public post<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
        return this.instance.post(url, data, { ...config });
    }

    // 上传请求
    public upload<T = any>(url: string, data?: any, config?: AxiosRequestConfig): Promise<T> {
        const formData = new FormData();
        if (data) {
            Object.keys(data).forEach((key) => {
                formData.append(key, data[key]);
            });
        }
        return this.instance.post(url, formData, {
            ...config,
            headers: {
                'Content-Type': 'multipart/form-data',
                ...(config?.headers || {}),
            },
        });
    }
}
文章目录