[axios] interceptors 实现原理

2019-12-25  本文已影响0人  小黄人get徐先生

官网链接:interceptors

你可以拦截请求或者响应在它们被 then 方法或者 catch 方法处理之前。

// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
    // 请求发送前的处理
    return config;
  }, function (error) {
    // 请求发送错误的处理
    return Promise.reject(error);
  });

// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
    // 2xx 状态码的情况将触发这个函数的执行,处理响应数据
    return response;
  }, function (error) {
    // 非 2xx 状态码情况将触发这个函数,处理响应错误
    return Promise.reject(error);
  });

也可以移除之前添加的拦截器:

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

实现

types/index.ts

export interface ResolvedFn<T> {
  (val: T): T | Promise<T>
}

export interface RejectedFn {
  (error: any): any
}

core/interceptorManager.ts

import { RejectedFn, ResolvedFn } from '../types'

interface Interceptor<T> {
  resolved: ResolvedFn<T>
  rejected?: RejectedFn
}

// 拦截管理器类,这里使用 T 类型是因为请求拦截器是 resovle 方法处理配置(AxiosRequestConfig),响应拦截器 resolve 方法处理响应数据( AxiosResponse )
export default class InterceptorManager<T> {
  private interceptors: Interceptor<T>[];

  constructor() {
    this.interceptors = [];
  }

  // 添加拦截器
  use(resolved: ResolvedFn<T>, rejected?: RejectedFn): number {
    this.interceptors.push({
      resolved,
      rejected
    });
    return this.interceptors.length - 1;
  }

  // 遍历拦截器,并执行 fn 方法
  forEach(fn: (interceptor: Interceptor<T>) => void): void {
    this.interceptors.forEach(interceptor => {
      if (interceptor !== null) {
        fn(interceptor);
      }
    });
  }

  // 移除拦截器
  eject(id: number): void {
    if (this.interceptors[id]) {
      this.interceptors[id] = null;
    }
  }
}

core/Axios.ts

import { AxiosPromise, AxiosRequestConfig, AxiosResponse, RejectedFn, ResolvedFn } from '../types'
import dispatchRequest from './dispatchRequest'
import InterceptorManager from './interceptorManager'
import mergeConfig from './mergeConfig'

interface Interceptors {
  request: InterceptorManager<AxiosRequestConfig>
  response: InterceptorManager<AxiosResponse>
}

interface PromiseChain<T> {
  resolved: ResolvedFn<T> | ((config: AxiosRequestConfig) => AxiosPromise<T>)
  rejected?: RejectedFn
}

export default class Axios {

  defaults: AxiosRequestConfig; // 默认配置相关,可以不用关心
  interceptors: Interceptors;

  constructor(initConfig: AxiosRequestConfig) {
    this.defaults = initConfig; // 默认配置相关,可以不用关心
    this.interceptors = {
      request: new InterceptorManager<AxiosRequestConfig>(),
      response: new InterceptorManager<AxiosResponse>()
    };
  }

  request(url: any, config?: any): AxiosPromise {
    // 重载实现
    if (typeof url === 'string') {
      if (!config) {
        config = {};
      }
      config.url = url;
    } else {
      config = url;
    }

    // 配置合并相关,这里不用关心
    config = mergeConfig(this.defaults, config);

    // 初始化链式调用列表如下,然后通过 interceptorManager 的 forEach 在列表前(request)或列表后(response)填完拦截器方法
   // request interceptor -> request interceptor -> dispatchRequest -> response interceptor -> response interceptor
    const chain: PromiseChain<any>[] = [{
      resolved: dispatchRequest,
      rejected: undefined
    }];

    // 头加方式添加请求拦截器到 chain 中
    this.interceptors.request.forEach(interceptor => {
      chain.unshift(interceptor);
    });

   // 尾加方式添加响应拦截器到 chain 中
    this.interceptors.response.forEach(interceptor => {
      chain.push(interceptor)
    });

    let promise = Promise.resolve(config);

    // 链式调用
    while (chain.length) {
      const { resolved, rejected } = chain.shift()!;
      promise = promise.then(resolved, rejected);
    }

    return promise;
  }

上一篇 下一篇

猜你喜欢

热点阅读