You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Axios创建的实例无法返回错误,拦截器失效问题排查

问题: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>)
}

问题分析与解决方法

核心原因排查

  1. 环境变量加载异常:
    Next.js中只有前缀为NEXT_PUBLIC_的环境变量能在客户端访问,如果NEXT_PUBLIC_BACKEND_URL未正确配置或未重启开发服务器,会导致Axios实例的baseURL为undefined,请求URL变成相对当前页面的路径,引发请求失败。此时错误属于请求级错误,不会触发拦截器中422状态码的判断逻辑,但拦截器仍然会reject错误。

  2. 错误处理逻辑缺陷:
    saveAdmin函数在catch块中直接返回错误,而onSubmit中未区分成功/失败的返回值。当请求失败时,返回的错误对象可能因类型或结构问题,在打印时被误判为undefined;同时这种方式模糊了成功与失败的边界,不利于后续逻辑处理。

解决步骤

  1. 验证环境变量:
    在组件或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开发服务器。

  2. 修改错误处理逻辑:
    将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);
        // 这里可以添加错误提示等逻辑
      }
    };
    
  3. 验证拦截器注册:
    在拦截器初始化代码中添加日志,确认拦截器是否被正确触发:

    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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 00:23:10