使用Axios创建的实例无法返回错误,拦截器失效问题排查
axios.post却正常 问题概述
我通过单例模式创建了Axios实例类,在React组件中调用该实例发起请求时,拦截器无法正确返回错误,saveAdmin函数返回的结果最终是undefined;但直接使用全局axios.post()调用时,saveAdmin能正常捕获并返回错误。
相关代码
Axios单例工具类(httpApi.ts)
import Axios, { AxiosInstance, AxiosResponse, AxiosError } from "axios"; class httpApiService { public server: AxiosInstance; public client: AxiosInstance; private static instance: httpApiService; constructor() { this.server = this.createAxiosInstance(process.env.BACKEND_URL); this.client = this.createAxiosInstance(process.env.NEXT_PUBLIC_BACKEND_URL); this.initializeInterceptors(this.client); this.initializeInterceptors(this.server); } public static getInstance(): httpApiService { if (!httpApiService.instance) { httpApiService.instance = new httpApiService(); } return httpApiService.instance; } private createAxiosInstance(baseURL: string | undefined): AxiosInstance { const configuration = { baseURL, headers: { "X-Requested-With": "XMLHttpRequest", }, withCredentials: true, withXSRFToken: true, }; if (typeof baseURL === "undefined") { delete configuration.baseURL; } let instance = Axios.create(configuration); return instance; } private initializeInterceptors(instance: AxiosInstance): void { instance.interceptors.response.use( (response: AxiosResponse) => { return response; }, (error: AxiosError) => { if (error.response?.status === 422) { console.error("Validation error: ", error.response.data); } return Promise.reject(error); } ); } } const httpApi = httpApiService.getInstance(); export default httpApi;
React组件调用代码(Page.tsx)
import httpApi from "@/utils/httpApi"; const saveAdmin = async (formData: saveAdminData) => { try { const response = await httpApi.client.post("/api-admin/admin", formData); return response; } catch (error) { console.log(error); return error; } }; const Page = () => { const onSubmit: SubmitHandler<adminData> = async ( data: adminData ): Promise<void> => { let formData: saveAdminData = { role_id: data.roles, username: data.username, email: data.email, password: data.password, password_confirmation: data.password_confirm, }; const response = await saveAdmin(formData); console.log(response); // 输出UNDEFINED }; return (<div> Remaining code ....</div>) }
问题分析与解决方法
核心原因排查
环境变量加载异常:
Next.js中只有前缀为NEXT_PUBLIC_的环境变量能在客户端访问,如果NEXT_PUBLIC_BACKEND_URL未正确配置或未重启开发服务器,会导致Axios实例的baseURL为undefined,请求URL变成相对当前页面的路径,引发请求失败。此时错误属于请求级错误,不会触发拦截器中422状态码的判断逻辑,但拦截器仍然会reject错误。错误处理逻辑缺陷:
saveAdmin函数在catch块中直接返回错误,而onSubmit中未区分成功/失败的返回值。当请求失败时,返回的错误对象可能因类型或结构问题,在打印时被误判为undefined;同时这种方式模糊了成功与失败的边界,不利于后续逻辑处理。
解决步骤
验证环境变量:
在组件或Axios实例初始化代码中打印环境变量,确认NEXT_PUBLIC_BACKEND_URL是否正确加载:console.log("Client baseURL:", process.env.NEXT_PUBLIC_BACKEND_URL);若输出
undefined,需在.env文件中添加NEXT_PUBLIC_BACKEND_URL=https://你的API地址,并重启Next.js开发服务器。修改错误处理逻辑:
将saveAdmin的错误处理改为抛出错误,在onSubmit中通过try-catch明确区分成功与失败场景:const saveAdmin = async (formData: saveAdminData) => { try { const response = await httpApi.client.post("/api-admin/admin", formData); return response; } catch (error) { console.log("Request error:", error); throw error; // 抛出错误而非返回 } }; // 组件内的onSubmit函数 const onSubmit: SubmitHandler<adminData> = async (data: adminData): Promise<void> => { let formData: saveAdminData = { role_id: data.roles, username: data.username, email: data.email, password: data.password, password_confirmation: data.password_confirm, }; try { const response = await saveAdmin(formData); console.log("Request success:", response); } catch (error) { console.log("Submit failed:", error); // 这里可以添加错误提示等逻辑 } };验证拦截器注册:
在拦截器初始化代码中添加日志,确认拦截器是否被正确触发:private initializeInterceptors(instance: AxiosInstance): void { console.log("Registering interceptors for instance"); instance.interceptors.response.use( (response: AxiosResponse) => { console.log("Response interceptor triggered (success)"); return response; }, (error: AxiosError) => { console.log("Response interceptor triggered (error)"); if (error.response?.status === 422) { console.error("Validation error: ", error.response.data); } return Promise.reject(error); } ); }
内容的提问来源于stack exchange,提问作者desh

