1. 程式人生 > 程式設計 >淺談axios中取消請求及阻止重複請求的方法

淺談axios中取消請求及阻止重複請求的方法

目錄
  • 前言
  • 核心——CancelToken
  • 實際應用和封裝
  • 一些小細節

前言

在實際專案中,我們可能需要對請求進行“防抖”處理。這裡主要是為了阻止使用者在某些情況下短時間內重複點選某個按鈕,導致前端向後端重複傳送多次請求。這裡我列舉兩種比較常見的實際情況:

  • PC端 - 使用者雙擊搜尋按鈕,可能會觸發兩次搜尋請求
  • 移動端 - 因移動端沒有點選延遲,所以極易造成誤操作或多操作,造成請求重發

以上情況有可能在有Loading遮罩時依然發生,所以我們要考慮前端阻止重複請求的方法。

核心——CancelToken

在Axios中取消請求最核心的方法是CanelToken。在官網文件中有寫到兩種方法使用CancelToken,這裡簡單粘貼出來,並增加了註釋

方法1:

const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345',{
  // 必須對請求進行cancelToken設定
  cancelToken: source.token
}).catch(function (thrown) {
  // 如果請求被取消則進入該方法判斷
  if (axios.isCancel(thrown)) {
    console.log('Request cXkXTkanceled',thrown.message);
  } else {
    // handle error
  }
});

// 取消上面的請求
// source.cancel('messge') message為可選項,必須為String
source.cancel('Operation canceled by the user.');

方法2:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345',{
  // 在options中直接建立一個cancelToken物件
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});

// 取消上面的請求
cancel();

實際應用和封裝

上文已對axios中的核心方法進行了舉例,但是在實際中我們往往不會像官網例子中那樣使用,更多的是在axios的攔截器中做全域性配置管理。這樣的話我們需要對上面的程式碼進行一些改變。

這裡說一下我實現的大體思路:

  • 我們需要對所有正在進行中的請求進行快取。在請求發起前判斷快取列表中該請求是否正在進行,如果有則取消本次請求。
  • 在任意請求完成後,需要在快取列表中刪除該次請求,以便可以重新發送該請求

思路說完,我們直接上程式碼

// 正在進行中的請求列表
let reqList = []

/**
 * 阻止重複請求
 * @param {array} reqList - 請求快取列表
 * @param {string} url - 當前請求地址
 * @param {function} cancel - 請求中斷函式
 * @param {string} errorMessage - 請求中斷時需要顯示的錯誤資訊
 */
const stopRepeatRequest = function (reqList,url,cancel,errorMessage) {
  const errorMsg = errorMessage || ''
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      cancel(errorMsg)
      return
    }
  }
  reqList.push(url)
}

/**
 * 允許某個請求可以繼續進行
 * @param {array} reqList 全部請求列表
 * @param {string} url 請求地址
 */
conhttp://www.cppcns.comst allowRequest = function (reqList,url) {
  for (let i = 0; i < reqList.length; i++) {
    if (reqList[i] === url) {
      reqList.splice(i,1)
      break
    }
  }
}

const service = axios.create()

// 請求攔截器
service.interceptors.request.use(
  config => {
 let cancel
   // 設定cancelToken物件
    config.cancelToken = new axios.CancelToken(function(c) {
     cancel = c
    })
    // 阻止重複請求。當上個請求未完成時,相同的請求不會進行
    stopRepeatRequest(reqList,config.url,`${config.url} 請求被中斷`)
    return config
  },err => Promise.reject(err)
)

// 響應攔截器
service.interceptors.response.use(
  response => {
    // 增加延遲,相同請求不得在短時間內重複傳送
    setTimeout(() => {
      allowRequest(reqList,response.config.url)
    },1000)
    // ...請求成功後的後續操作
    // successHandler(response)
  },error => {
    if (axios.isCancel(thrown)) {
      console.log(thrown.message);
    } else {
      // 增加延遲,相同請求不得在短時間內重複傳送
      setTimeout(() => {
        allowRequest(reqList,error.config.url)
      },1000)
    }
    // ...請求失敗後的後續操作
    // errorHandler(error)
  }
)

一些小細節

為什麼沒用前文方法2中的程式碼進行cancelToken設定?
axios的文件中有一條備註:

Note: you can cancel several requests with the same cancel token.
你可以使用相同的Token來取消多個請求

所以我不想在每個請求前都new一個新的物件
請務必使用方法2,保證每次cancel都能正確執行。之前方法會導致當出現cancel後,後續請求也會持續cancel

為什麼在response中需要增加延遲?
因為不想讓使用者在極短的時間內重複進行相同請求。
請注意,在response中阻止請求和在request中的阻止請求是兩個概念:
request中是阻止上個請求 未完成 時又開始了相同的請求
response中是阻止上個請求 完成後 一段時間內不允許相同請求

我能否在cancel時傳遞一個物件,而不僅僅是message?
以官方提供的介面來看是不可以的,你可以仿照官方原始碼進行重新封裝,或者使用第三方外掛,或者使用另一個方法:將物件轉換為ON字串,然後在需要的地方再轉換回來

到此這篇關於淺談axios中取消請求及阻止重複請求的方法的文章就介紹到這了,更多相關awww.cppcns.comxios中取消請求及阻止重複請求內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!