Vue路由切換 & Axios介面取消重複請求

南城大前端發表於2022-04-29
在日常前端開發中, 經常會遇到頻繁發起的重複請求, 會給伺服器及網路造成不必要的壓力, 可通過取消重複請求解決

場景

  • 訂單資料條件篩選查詢
  • 表單提交按鈕頻繁點選
  • 路由頁面切換請求未取消

解決方案

在每個請求發起的時候儲存當前儲存的標記在一個陣列或Map中, 針對每個請求的時候在請求攔截中查詢是否重複, 如果已重複則取消歷史中重複的請求, 再發起當前請求, 如果沒有重複, 則新增儲存標記並正常請求, 已請求完成的清除儲存標記

axios中如何取消請求

  1. 可以使用 CancelToken.source 工廠方法建立 cancel token,像這樣:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
     // 處理錯誤
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消請求(message 引數是可選的)
source.cancel('Operation canceled by the user.');
  1. 還可以通過傳遞一個 executor 函式到 CancelToken 的建構函式來建立 cancel token:
const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // executor 函式接收一個 cancel 函式作為引數
    cancel = c;
  })
});

// cancel the request
cancel();

專案中封裝使用

基本變數定義

// 是否取消重複請求開關
const cancelDuplicated = true

// 儲存每個請求中的map
const pendingXHRMap = new Map()

// 取消請求型別定義 便於後期對此型別不做異常處理
const REQUEST_TYPE = {
  DUPLICATED_REQUEST: 'duplicatedRequest'
}

設定重複標記的函式

const duplicatedKeyFn = (config) => {
  // 可在此設定使用者自定義其他唯一標識 預設按請求方式 + 請求地址
  return `${config.method}${config.url}`
}

新增到請求記錄

const addPendingXHR = (config) => {
  if (!cancelDuplicated) {
    return
  }
  const duplicatedKey = JSON.stringify({
    duplicatedKey: duplicatedKeyFn(config),
    type: REQUEST_TYPE.DUPLICATED_REQUEST
  })
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (duplicatedKey && !pendingXHRMap.has(duplicatedKey)) {
      pendingXHRMap.set(duplicatedKey, cancel)
    }
  })
}

刪除請求記錄

const removePendingXHR = (config) => {
  if (!cancelDuplicated) {
    return
  }
  const duplicatedKey = JSON.stringify({
    duplicatedKey: duplicatedKeyFn(config),
    type: REQUEST_TYPE.DUPLICATED_REQUEST
  })
  if (duplicatedKey && pendingXHRMap.has(duplicatedKey)) {
    const cancel = pendingXHRMap.get(duplicatedKey)
    cancel(duplicatedKey)
    pendingXHRMap.delete(duplicatedKey)
  }
}

axios中使用

// 請求攔截處理
axios.interceptors.request.use(config => {
    removePendingXHR(config)
    addPendingXHR(config)
    ...
    return config
})

// 響應攔截處理
axios.interceptors.response.use(response => {
    removePendingXHR(response.config)
    ...
}, error => {
    // 如果是取消請求型別則忽略異常處理
    let isDuplicatedType;
    try {
      const errorType = (JSON.parse(error.message) || {}).type
      isDuplicatedType = errorType === REQUEST_TYPE.DUPLICATED_REQUEST;
    } catch (error) {
      isDuplicatedType = false
    }
    if (!isDuplicatedType) {
        // 其他異常處理
    }
})

Vue中當路由切換頁面的時候,將上一個頁面的所有請求取消

router.beforeEach((to, from, next) => {
    // 遍歷pendingMap,將上一個頁面的所有請求cancel掉
    pendingXHRMap.forEach((cancel) => {
        cancel();
    });
    pendingXHRMap.clear()
})

總結

本文主要介紹了在日常前端開發中, 遇到各種情況下頻繁發起的重複請求, 會給伺服器及網路造成不必要的壓力, 可通過取消重複請求解決。

專注前端開發,分享前端相關技術乾貨,公眾號:南城大前端(ID: nanchengfe)

參考

axios官網取消請求

如何優雅的解決”重複請求“問題

相關文章