基於 TS 實現 axios(五)

今天這一章節主要介紹 攔截器

目錄結構:

在這裏插入圖片描述

攔截器

先問什麼是攔截器?

可以從字面意思理解大概就是攔截數據,主要運用在發起請求前或請求返回數據後對數據進行處理,可以運用在登錄、處理一些格式化數據之類的。

按照請求的時間不同分爲:請求前的 請求攔截器,請求後的 響應攔截器

types/index.ts 中新增代碼

// ...
// 最後加入
export interface AxiosInterceptorManage<T>{
    use(resolved:ResolvedFn<T>,rejected?:RejectedFn):number,

    eject(id:number):void
}

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

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

其中 <T> 表示 泛型 (之前說過的)

新增文件 core/InterceptorManager.ts

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

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

}

export default class InterceptorManager<T>{
    private interceptors:Array<Interceptor<T> | null>

    constructor(){
        this.interceptors = []
    }
    use(resolved:ResolvedFn<T>,rejected?:RejectedFn):number{
        this.interceptors.push({
            resolved,
            rejected,
        })
        return this.interceptors.length -1;
    }

    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;
        }
    }
}

定義一個 InterceptorManager 類,其中有一個 use 方法,主要用來將回調函數添加到 interceptors 中,並返回其下標eject 方法用在下標刪除回調函數; forEach 遍歷回調函數

core/Axios.ts

// ...

import InterceptorManager from './InterceptorManager';

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

interface PromiseChain<T> {
    resolved:ResolvedFn<T> | ((config:AxiosRequestConfig) => AxiosPromise)
    rejected?:RejectedFn, 
}
export default class Axios{
    interceptors: Interceptors
    constructor(){
        this.interceptors = {
            request : new InterceptorManager<AxiosRequestConfig>(),
            response :new InterceptorManager<AxiosResponse>(),
        }
    }
    request(url: any, config?:any):AxiosPromise {
		// ...
        
        const chain:PromiseChain<any>[] = [{
            resolved: dispatchRequest,
            rejected: undefined,
        }]	// 添加要發起請求
        this.interceptors.request.forEach(interceptor => {
            chain.unshift(interceptor)
        })	// 請求攔截器放在 請求 前

        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);
        }	// 遍歷 chain ,實現調用
		

        return promise;
    }
    
    // ...
}

這一段代碼是核心代碼,將所有的攔截器和請求放在 chain 數組中,依次彈出借用 Promise 執行。

實現調用:

import axios from '../../src/index'

axios.interceptors.request.use(config => {
  config.headers.test += '1'
  return config
})
axios.interceptors.request.use(config => {
  config.headers.test += '2'
  return config
})
axios.interceptors.request.use(config => {
  config.headers.test += '3'
  return config
})
axios.interceptors.response.use(res => {
  res.data += '1'
  return res
})
let interceptor = axios.interceptors.response.use(res => {
  res.data += '2'
  return res
})
axios.interceptors.response.use(res => {
  res.data += '3'
  return res
})

axios.interceptors.response.eject(interceptor)


axios({
  url: '/interceptor/get',
  method: 'get',
  headers: {
    test: ''
  }
}).then((res) => {
  console.log(res.data)
})

返回的數據會多加 13,而 headers.test 等於 321

注意:請求攔截器越後面註冊就越靠前,響應攔截器反之。因爲請求攔截器用的是 unshift,響應攔截器用的是 push

就寫到這裏吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章