原文地址:如何优雅地管理HTTP请求和响应拦截器

公众号:前端自习课

作者:王平安

作者介绍了他重构老项目的axios拦截器、封装请求API的思路和优化点。

作者参考“插件化架构设计”,将每个拦截器抽离为独立文件,保证拦截器职责单一,随时可增删。

封装后的request目录如下:

第一步 axios 拦截器的使用与注册

关键在于调用axios.interceptors 这个对象上的 requestresponse use 方法

传入两个回调函数(成功或失败)来处理请求时的 config 或响应时的 response

不论请求或响应都可能会有多个拦截器,此时需要遍历拦截器函数一次调用 use 函数来注册

export const interceptor = {
    request,
    response
};

export const runInterceptors = instance => {

    // 设置请求拦截器
    for (const key in request) {
      const { success, error } = request[key];
      axios.interceptors.request.use(success, error);
    }
  
    // 设置响应拦截器
    for (const key in response) {
      const { success, error } = response[key];
      axios.interceptors.response.use(success, error);
    }
  
    return axios;
}

第二步 定义具体的拦截器

根据业务需要来声明拦截器,请求拦截器接收 config 作为参数,最后一定会返回 config;响应拦截以 response 作为参数,最后返回 response

例如:

const setLoading = options => {
  log("[interceptor.request]setLoading:", options);

  Toast.loading({
    duration: 0,
    message: '加载中...',
    forbidClick: true,
  });
  return options;
};

export default setLoading;

//  src/request/interceptors/request/index.js
import setLoading from './setLoading';

export default [
    setLoading
];

最后将所有请求或响应拦截器导出为一个数组,方便遍历注册。

第三步 封装整个请求

通过 axios.create 创建一个 axios 请求实例,调用 runInterceptors() 来给这个实例依次注册拦截器,最后导出该 request

第四步 业务中调用请求API


import request from './../request/index.js';

const send = async () => {
  const result = await request({
    url: 'https://httpbin.org/headers',
    method: 'get'
  })
}

第五步 思考哪些地方还可以进一步优化?

1、请求层是否可以独立成库?

2、是否可以随时更换请求库?需要在已有请求层再抽象一层请求库适配层

3、开发拦截器脚手架,按照内置模板声明拦截器,这样能保证使用规范

4、考虑更多情况:拦截器失败时如何处理?拦截器的调用顺序?Tapable插件机制是否可参考?

我的思考

厘清当前代码的缺陷和想要实现的业务需求,是重构和封装的出发点。不需要急着实现多复杂的功能(我可能一上来就会思考第五步中的各种进阶或特殊需求)先能满足当前使用。