以配置的方式開關axios攔截器功能

前景提要:
ts 簡易封裝 axios,統(tǒng)一 API

背景

axios 很多額外功能都是基于攔截器實現(xiàn)。有些功能想要全局使用,因此將攔截器注冊在全局。比如重復請求過濾。但也有一小部分請求不希望進行過濾,比如并發(fā)上傳文件。

因此希望可以在具體的請求方法上,通過配置 config 從而決定針對當前請求,某個攔截器是否啟用。

  • 默認不寫配置項或者標為 true,都是開啟。
  • 明確指定配置項為 false,才是關閉。

注意:在具體方法上配置時,沒有明確配置為 true 時,可能沒有開啟功能。因為在實例化時的 config 對象上,可能將該功能設為 false 了。整個 axios 實例上關閉了該功能,則此時具體方法上必須明確設為 true 覆蓋掉實例化的配置才能啟用。

以當前請求是否開啟響應反饋為例:

// index.ts

import HttpRequest from "./http/request";

// 實例化 axios
const httpRequest = new HttpRequest({
    baseURL: import.meta.env.VITE_APP_API_BASE_URL,
    timeout: import.meta.env.VITE_APP_API_TIMEOUT,
    // 開啟響應反饋攔截器功能(注冊攔截器后,默認就是開啟)
    showMessage: true 
});

// 在該 axios 實例上注冊請求響應反饋攔截器
httpRequest.getInstance().interceptors.response.use(responseMessageOnFulfilled, null);
// 默認開啟當前請求的請求響應彈窗反饋
async function handleMessageOpen() {
    const res = await httpRequest.get({
        url: "/mock/test"
    });
    console.log("res", res);
}

// 手動關閉當前請求的響應反饋
async function handleMessageClose() {
    const res = await httpRequest.get({
        url: "/mock/test",
        showMessage: false
    });
    console.log("res", res);
}

擴展 config 類型

給 axios config 對象添加額外配置項,首先得擴充它的類型AxiosRequestConfig

// 開關的默認值(默認都是開啟)
const DEFAULT_EXTRA_FEATURE_CONFIG = { showMessage: true };

/** 擴展 axios 的請求配置類型 */
export interface MyAxiosRequestConfig<TReqBodyData = any> extends AxiosRequestConfig<TReqBodyData> {
    showMessage?: boolean; // 是否開啟請求反饋提示框
}

攔截器中也需要用到 config 對象。但是在最新的 axios 中,請求攔截器中 config 的類型不再是 AxiosRequestConfig,而是InternalAxiosRequestConfig。因此還需要擴展一下請求攔截器 configInternalAxiosRequestConfig類型。

/** 給攔截器使用 */
export interface MyInternalAxiosRequestConfig extends InternalAxiosRequestConfig {
    showMessage?: boolean;
}

有些功能在響應攔截器 onFulfilled 回調(diào)中完成,如響應反饋,也有些在 onRejected 回調(diào)中完成,如請求重試。因此也需要擴展響應攔截器中的回調(diào),AxiosResponseAxiosError里的 config 對象類型。

export interface MyAxiosResponse extends AxiosResponse {
    config: MyInternalAxiosRequestConfig;
}

export interface MyAxiosError extends AxiosError {
    config: MyInternalAxiosRequestConfig;
}

將額外配置項注入響應攔截器

實現(xiàn)各種功能的攔截器,可能是請求攔截器,也可能是響應攔截器。請求攔截器中可以很輕易拿到具體方法 config 上填寫的配置項。但是響應攔截器卻不好拿,因為 AxiosResponse 實例上的 config 對象是新生成的,它沒有我們額外補充的配置項。

因此,我們需要在請求攔截器中先手動保存用戶填寫的配置項的值,然后在響應攔截器中手動添加到 config 對象上。并且該響應攔截器必須是最先執(zhí)行的響應攔截器。

class HttpRequest {
    private readonly instance: AxiosInstance;
        private readonly extraConfig: Record<string, boolean> = DEFAULT_EXTRA_FEATURE_CONFIG;

    constructor(config: MyAxiosRequestConfig) {
        this.instance = axios.create(config);
    
        // 記錄 config 額外配置項
        this.instance.interceptors.request.use((config: MyInternalAxiosRequestConfig) => {
            Object.keys(this.extraConfig).forEach(item => {
                if (config[item as keyof MyInternalAxiosRequestConfig] === false)
                    this.extraConfig[item] = !!config[item as keyof MyInternalAxiosRequestConfig];
            });
            return config;
        });
        // 將配置項補充到響應的 config 對象上
        this.instance.interceptors.response.use(
            (res: any) => {
                Object.keys(this.extraConfig).forEach(item => {
                    res.config[item] = this.extraConfig[item];
                    this.extraConfig[item] = true; // 配置復原成默認開啟
                });
                return res;
            },
            (err: any) => {
                Object.keys(this.extraConfig).forEach(item => {
                    err.config[item] = this.extraConfig[item];
                    this.extraConfig[item] = true; // 配置復原成默認開啟
                });
                throw err;
            }
        );
    }

    ...
}

請求響應反饋攔截器

// src\api\http\message.ts

import { MyAxiosResponse } from "./request";

// 假設接口:{code: number, data: any, msg: string}
function showMessage(res: MyAxiosResponse) {
    const { data } = res;
    // alert 消息提示
    if (data.code >= 200 && data.code < 300) alert(data.msg);
    return res;
}

/**
 * 響應業(yè)務消息提示
 */
export function responseMessageOnFulfilled(res: MyAxiosResponse) {
    if (res.config.showMessage) showMessage(res); // showMessage 為 true,才給出反饋
    return res;
}

使用示例

<template>
  <div>
    <button @click="handleMessageOpen">message消息提示開</button>
    <button @click="handleMessageClose">message消息提示關</button>
  </div>
</template>

<script setup lang="ts">
  import HttpRequest from "./http/request";
  import { responseMessageOnFulfilled } from "./http/message";

    // 實例化
  const httpRequest = new HttpRequest({
    baseURL: "/",
    timeout: 10000
  });

  // 注冊攔截器
  httpRequest.getInstance().interceptors.response.use(responseMessageOnFulfilled);

  // 反饋默認開
  async function handleMessageOpen() {
    const res = await httpRequest.get({
      url: "/__api/mock/get_test"
      // showMessage: true
    });
    console.log("res", res);
  }

  // 手動關閉反饋
  async function handleMessageClose() {
    const res = await httpRequest.get({
      url: "/__api/mock/get_test",
      showMessage: false
    });
    console.log("res", res);
  }
</script>

結果:


axios響應反饋.gif

總結

通過在 config 對象上添加額外配置的方式來實現(xiàn)針對某個請求開關某個攔截器的目標。

  1. 擴展 config 類型
  2. 將額外配置項從請求 config 保存到 響應 config 對象上
  3. 編寫具體功能的攔截器
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容