在二次封装axios时,如何选择封装方式?

新手上路,请多包涵

关于 axios 二次封装方法的问题

  1. 通过 class 创建多个实例

    class Http {
       ...
    }
    const http1 = new Http()
    const http2 = new Http()
  2. 仅通过 axios 创建一个实例

    import axios from 'axios'
    
    const axiosInstance = axios.create({
       baseURL: import.meta.env.VITE_APP_BASE_URL,
       timeout: 5000
    })
    
    export default axiosInstance

哪种方法更好些呢?或者大家有更好的封装思路吗?

看了一些博客,关于用 class 包装的 axios, 给出来的好处是 不同的服务可以加不同的拦截器,我刚工作不久,不知道有什么场景需要用到这种需求。我更偏向于第二种方法,感觉我接触到的服务,只需要切换一下 baseUrl,并没有别的需求了。

阅读 2k
avatarAI BotBETA

在二次封装 axios 时,选择封装方式需要考虑实际需求和项目规模。

如果你希望为不同的服务使用不同的拦截器或配置,那么通过 class 创建多个实例可能是更好的选择。这种方式可以让你为每个服务独立设置拦截器和配置,使得代码更具可维护性和灵活性。例如,你可以为 API 请求较多的服务设置一个特定的拦截器来记录请求日志,而对于其他服务则不需要这个拦截器。

另外,如果你只是需要切换 baseUrl,那么通过 axios 创建一个实例可能更为简洁和方便。这种方式可以让你在整个项目中共享同一个 axios 实例,避免了重复的配置和初始化工作。同时,你可以通过配置该实例来统一管理请求的拦截器和超时时间等。

除了以上两种方式,还有其他的封装思路可供选择。例如,你可以使用工厂函数来创建 axios 实例,以便根据不同的参数返回不同的配置。或者你可以使用第三方库(如 axios-mock-adapter)来模拟 axios 请求,以便在测试中控制和模拟请求响应。

总之,选择合适的封装方式取决于你的实际需求和项目规模。在实践中,可以根据具体情况进行尝试和调整,以找到最适合你的方式。

5 个回答

这个根据业务决定,你可问问你们后端,同时方法二也可以创建一个新的 axios 实例进行拓展啊,这种不需要考虑太多,两种都具备向后拓展的空间

总的来说,需求决定架构,按照你举的例子稍微分析一下

  • 第一种方式更适合,一个系统需要对接多个服务端提供的API,且多个服务端用的不是同一种标准,比如 baseUrl 不同,认证方式不同等等
  • 第二种就是常规的配置,对接单个服务端绰绰有余

如果项目有自己的业务后端的话,前端基本上不需要考虑这个问题,通常会在业务后端把差异抹平,对于前端来说始终是一套标准。大厂一般都会用 node 做一个 BFF 层来实现,不过通常也是由前端开发的,俗称大前端

这取决于你要不要对 axios 的行为进行于次封装。创建对象是用 new 还是用 create 并不重要,重要的是需要创建什么对象。

比如 class Http 是对 axios 的行为进行了封装(比如需要应用适配器模式),那么题中提到的两种方式分别对应

// 第一种方式,在 Http 内部产生 Axios 对象
const http1 = new Http();
// 第二种方式,外面产生一个 Axios 对象并注入到 Http 中
const a = axios.create(...);
const http1 = new Http(a);

// 或者合并成一句
const http2 = new Http(axios.create(...));

如果你只是需要 axios 对象,不需要 Http 对象,但是又需要根据不同的场景使用不同的参数来创建 axios 对象,那么不需要封装成对象,直接使用多个方法,甚至简单工厂、工厂方法都是可以的,比如

function createAxiosForService1() {
    return axios.create(...);
}

function createAxiosForService2() {
    return axios.create(...);
}

或者

function createAxiosFor(type) {
    switch(type) {
        ...
    }
}

或者用一个命名空间(类)把这些方法收集在一起

class AxiosFactory {
    static forService1() { return axios.create(...); }
    static forService2() { return axios.create(...); }
}

当然,既然可以用工厂方法,那说明在复杂一点的场景下,使用抽象工厂也是可以。这个就可以根据上面的提示自己去研究研究一。

我更推荐第二种封装方式,这样创建出来的实例,能保留axios原版的配置和方法。若是用class封装,还得自己再写一套方法,然后再调用axios里的方法。

通过 axios.create() 创建实例的方式,也可以创建出不同的实例。

const create = (config) => {
    const axiosInstance = axios.create(config);
    axiosInstance.interceptors.request.use(); // 添加拦截器
    return axiosInstance;
}

const http1 = create({ baseURL: 'http://a.com' });
const http2 = create({ baseURL: 'http://b.com' });

这两种封装的分层都不一样

第一种实际不应该是泛用的 Http ,而是和业务相关的 Client

class AliCloudClient {
    // 这个 axios 实例已经封装到 client 内了,使用者不需要关心 axios 的细节
    private client: AxiosInstance
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进