需求

请求之前拦截请求数据,响应之后拦截响应数据。

  • 可支持多个拦截器。
  • 可移除
  • 请求拦截器先添加,后执行,响应拦截器先添加先执行
    1. // 添加一个请求拦截器
    2. axios.interceptors.request.use(function (config) {
    3. // 在发送请求之前可以做一些事情
    4. return config;
    5. }, function (error) {
    6. // 处理请求错误
    7. return Promise.reject(error);
    8. });
    9. // 添加一个响应拦截器
    10. axios.interceptors.response.use(function (response) {
    11. // 处理响应数据
    12. return response;
    13. }, function (error) {
    14. // 处理响应错误
    15. return Promise.reject(error);
    16. });

    整体设计

    image.png
    形成一个Promise链式调用。

    定义拦截器管理类

    ```typescript import { ResolvedFn, RejectedFn } from “../types”

interface Interceptor { resolved: ResolvedFn rejected?: RejectedFn }

export class InterceptorManager { private interceptors: Array | null> = []

constructor() { this.interceptors = [] }

use(resolved: ResolvedFn, rejected?: RejectedFn) { this.interceptors.push({ resolved, rejected }) return this.interceptors.length - 1 }

eject(id: number) { if (this.interceptors[id]) { this.interceptors[id] = null } }

forEach(fn: (item: Interceptor) => void) { this.interceptors.forEach(interceptor => { if (interceptor) { fn(interceptor) } }) } }

  1. <a name="SROEO"></a>
  2. ## 实现整体设计,链式调用
  3. 在Axios类添加interceptors属性保存请求拦截管理器和响应拦截管理器,并且拼成一条promise链,连续调用。
  4. ```typescript
  5. import { AxiosPromise, AxiosRequestConfig, AxiosResponse, Method, RejectedFn, ResolvedFn } from '../types/index'
  6. import dispatchRequest from './dispacthRequest'
  7. import { InterceptorManager } from './interceptorManager'
  8. interface Interceptors {
  9. request: InterceptorManager<AxiosRequestConfig>
  10. response: InterceptorManager<AxiosResponse>
  11. }
  12. interface PromiseChain<T> {
  13. resolved: ResolvedFn<T> | ((config: AxiosRequestConfig) => AxiosPromise<T>)
  14. rejected?: RejectedFn
  15. }
  16. export default class Axios {
  17. interceptors: Interceptors
  18. constructor() {
  19. this.interceptors = {
  20. request: new InterceptorManager<AxiosRequestConfig>(),
  21. response: new InterceptorManager<AxiosResponse>()
  22. }
  23. }
  24. request(url: string | AxiosRequestConfig, config?: AxiosRequestConfig): AxiosPromise {
  25. // 重载
  26. if (typeof url === 'string') {
  27. if (!config) {
  28. config = {}
  29. }
  30. config.url = url
  31. } else {
  32. config = url
  33. }
  34. const chain: PromiseChain<any>[] = [
  35. {
  36. resolved: dispatchRequest,
  37. }
  38. ]
  39. // 请求拦截器,先添加,后调用
  40. this.interceptors.request.forEach(interceptor => {
  41. chain.unshift(interceptor)
  42. })
  43. // 响应拦截器,先添加,先调用
  44. this.interceptors.response.forEach(interceptor => {
  45. chain.push(interceptor)
  46. })
  47. let promise = Promise.resolve(config)
  48. while (chain.length) {
  49. const { resolved, rejected } = chain.shift()!
  50. promise = promise.then(resolved, rejected)
  51. }
  52. return promise as AxiosPromise
  53. }
  54. // _requestWithNoData
  55. get(url: string, config?: AxiosRequestConfig) {
  56. return this._requestWithNoData('get', url, config)
  57. }
  58. head(url: string, config?: AxiosRequestConfig) {
  59. return this._requestWithNoData('head', url, config)
  60. }
  61. delete(url: string, config?: AxiosRequestConfig) {
  62. return this._requestWithNoData('delete', url, config)
  63. }
  64. options(url: string, config?: AxiosRequestConfig) {
  65. return this._requestWithNoData('options', url, config)
  66. }
  67. // _requestWithData
  68. post(url: string, data?: any, config?: AxiosRequestConfig) {
  69. return this._requestWithData('post', url, data, config)
  70. }
  71. put(url: string, data?: any, config?: AxiosRequestConfig) {
  72. return this._requestWithData('put', url, data, config)
  73. }
  74. patch(url: string, data?: any, config?: AxiosRequestConfig) {
  75. return this._requestWithData('patch', url, data, config)
  76. }
  77. _requestWithNoData(method: Method, url: string, config?: AxiosRequestConfig) {
  78. return this.request(
  79. Object.assign(config || {}, {
  80. method,
  81. url
  82. })
  83. )
  84. }
  85. _requestWithData(method: Method, url: string, data?: any, config?: AxiosRequestConfig) {
  86. return this.request(
  87. Object.assign(config || {}, {
  88. method,
  89. url,
  90. data
  91. })
  92. )
  93. }
  94. }