Skip to content

插件化你的 axios 拦截器和工具, 使其更加容易复用.

License

Notifications You must be signed in to change notification settings

uioz/axios-pluginify

Repository files navigation

axios-pluginify

axios-pluginify 是一款极小的工具, 可以让 axios 成为基于插件的请求库.

通过这种方式使得 axios 可以与其结合的类库例如 axios-cache-adapter 以及拦截器功能进行解耦, 让它们更加容易组织和复用.

Install

npm install axios-pluginify

Usage

提示: axios (对象)本身可以用于请求也可以通过属性来配置, 同时还支持通过 create 方法来创建新的实例 axios-pluginify 利用了 create 方法, 下面的例子中使用 axiosInstanceaxiosStatic 将实例和 axios 本身进行区分.

自定义插件

const axiosStatic = require('axios');
const { pluginify } = require('axios-pluginify');

class Plugin {
  // 可选
  constructor(pluginConfig) {
    this.pluginConfig = pluginConfig;
  }

  // 可选 axios 实例化前创建
  beforeCreate(axiosConfig, axiosStatic) {
    console.log(this.pluginConfig);

    console.log(axiosConfig);

    console.log(axiosStatic);
  }

  // 可选 axios 实例化后创建
  created(axiosInstance, axiosConfig) {
    console.log(axiosInstance);

    console.log(axiosConfig);
  }
}

const axiosInstance = pluginify(axiosStatic).use(new Plugin()).generate();

axiosInstance.get('/users');

包装已有类库

const axiosStatic = require('axios');
const { default: MockAdapter } = require('axios-mock-adapter');
const { pluginify } = require('axios-pluginify');

class MockAdapterPlugin {
  created(axiosInstance) {
    const mock = new MockAdapter(axiosInstance);

    mock.onGet('/uesrs').reply(200, {
      msg: 'hello world',
    });
  }
}

const axiosInstance = pluginify(axiosStatic)
  .use(new MockAdapterPlugin())
  .generate();

axiosInstance.get('/users');

包装拦截器

const axiosStatic = require('axios');
const { pluginify } = require('axios-pluginify');

class RequestWithToken {
  constructor(token) {
    this.token = token;
  }
  created(axiosInstance) {
    axiosInstance.interceptors.request.use((config) => {
      config.headers['x-access-token'] = this.token;
    });
  }
}

class ExtractResultPlugin {
  created(axiosInstance) {
    axiosInstance.interceptors.response.use((response) => {
      if (response.status === 200) {
        return response.data;
      }
    });
  }
}

const axiosInstance = pluginify(axiosStatic)
  .use(new RequestWithToken('token'), new ExtractResultPlugin())
  .generate();

axiosInstance.get('/users');

API

pluginify

constructor

pluginify(axiosStatic);
pluginify(axiosStatic, {
  // 交由 axiosStatic.create() 所使用的配置, 可以被插件重写
});

use

const axiosPluginify = pluginify(axiosStatic);

axiosPluginify.use(new Plugin(), new Plugin(), new Plugin());

or

axiosPluginify.use(new Plugin()).use(new Plugin()).use(new Plugin());

generate

创建 axios 实例并结合 use 方法所给定的插件.

const axiosPluginify = pluginify(axiosStatic);

const axiosInstance = axiosPluginify.use(new Plugin()).generate();

通过向 generate 传入 true 表示生成 axiosInstance 后销毁 pluginify 内部保存的引用, 避免内存泄漏.

const axiosPluginify = pluginify(axiosStatic);

const axiosInstance = axiosPluginify.use(new Plugin()).generate(true);

destroy

用于销毁 pluginify 内部保存的引用, 可以通过 generate(true) 触发.

plugin

插件是一个类(也可以是一个构造函数), 可以提供数个生命周期钩子.

class Plugin {
  // optional
  constructor() {}

  // optional
  beforeCreate(axiosRequestConfig, axiosStatic) {}

  // optional
  created(axiosInstance, axiosRequestConfig) {}
}

definePlugin

定义一个插件, 效果和普通插件一样, 这个函数可以让你获取到语法提示:

const axiosStatic = require('axios');
const { definePlugin, pluginify } = require('axios-pluginify');

pluginify(axiosStatic)
  .use(
    definePlugin({
      apply() {},
      beforeCreate() {},
      created() {},
    })
  )
  .generate(true);

在这里 apply 替换了 class 中的 construtcor, 如果你使用 typescript 那么 apply 受到类型系统限制是必选的, 如果你忽略这个错误也不会有问题.

另外 definePlugin 上面的钩子只能使用传统的函数不能是箭头函数因为在 definePlugin 内部显示绑定了 this 而箭头函数无法进行绑定.

内置的插件

  • AxiosRetry
  • AxiosCacheAdapter

这两个插件分别对 axios-retryaxios-cache-adapter 做了插件化处理, 同时也是最基本的插件示例.

FAQ

我是否可以多次调用 generate 方法

可以, 不过 axios-pluginify 没有对 beforeCreatecreated 所传入的参数做任何处理.

如果你在这些钩子函数中修改了传入钩子的参数, 则需要考虑这些插件在后续 generate 调用的时候的逻辑.

一个更加简单的方式是复用生产出的 axios 实例, 而不是多次调用 generate 方法.

插件的执行顺序是怎样的

axios-pluginify 会按照 use 方法的执行顺序来处理它们的挂载.

唯一需要注意的是 axios 的拦截器是栈结构, 也就是说后挂载的拦截器先执行.