基于 axios 實(shí)現(xiàn)取消重復(fù)請求

Axios 是一個(gè)基于 Promise 的 HTTP 客戶端袖肥,同時(shí)支持瀏覽器和 Node.js 環(huán)境。它是一個(gè)優(yōu)秀的 HTTP 客戶端油狂,被廣泛地應(yīng)用在大量的 Web 項(xiàng)目中寸癌。

# 如何取消請求

對于瀏覽器環(huán)境來說蒸苇,Axios 底層是利用 XMLHttpRequest 對象來發(fā)起 HTTP 請求。如果要取消請求的話味咳,我們可以通過調(diào)用 XMLHttpRequest 對象上的 abort 方法來取消請求:

let xhr = new XMLHttpRequest();
xhr.open("GET", "https://developer.mozilla.org/", true);
xhr.send();
setTimeout(() => xhr.abort(), 300);

而對于 Axios 來說檬嘀,我們可以通過 Axios 內(nèi)部提供的 CancelToken 來取消請求

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

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

source.cancel('Operation canceled by the user.'); // 取消請求鸳兽,參數(shù)是可選的

此外,也可以通過調(diào)用 CancelToken 的構(gòu)造函數(shù)來創(chuàng)建 CancelToken全陨,具體如下所示:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  })
});

cancel(); // 取消請求

# 如何判斷重復(fù)請求

當(dāng)請求方式辱姨、請求 URL 地址和請求參數(shù)都一樣時(shí)戚嗅,我們就可以認(rèn)為請求是一樣的。因此在每次發(fā)起請求時(shí)镜悉,我們就可以根據(jù)當(dāng)前請求的請求方式侣肄、請求 URL 地址和請求參數(shù)來生成一個(gè)唯一的 key醇份,同時(shí)為每個(gè)請求創(chuàng)建一個(gè)專屬的 CancelToken吼具,然后把 key 和 cancel 函數(shù)以鍵值對的形式保存到 Map 對象中拗盒,使用 Map 的好處是可以快速的判斷是否有重復(fù)的請求:

import qs from 'qs'

const pendingRequest = new Map();
// GET -> params锥债;POST -> data
const requestKey = [method, url, qs.stringify(params), qs.stringify(data)].join('&'); 
const cancelToken = new CancelToken(function executor(cancel) {
  if(!pendingRequest.has(requestKey)){
    pendingRequest.set(requestKey, cancel);
  }
})

當(dāng)出現(xiàn)重復(fù)請求的時(shí)候哮肚,我們就可以使用 cancel 函數(shù)來取消前面已經(jīng)發(fā)出的請求,在取消請求之后恼策,我們還需要把取消的請求從 pendingRequest 中移除〕奔簦現(xiàn)在我們已經(jīng)知道如何取消請求和如何判斷重復(fù)請求,下面我們來介紹如何取消重復(fù)請求狮斗。

# 如何取消重復(fù)請求

因?yàn)槲覀冃枰獙λ械恼埱蠖歼M(jìn)行處理改含,所以我們可以考慮使用 Axios 的攔截器機(jī)制來實(shí)現(xiàn)取消重復(fù)請求的功能迄汛。Axios 為開發(fā)者提供了請求攔截器和響應(yīng)攔截器,它們的作用如下:

  • 請求攔截器:該類攔截器的作用是在請求發(fā)送前統(tǒng)一執(zhí)行某些操作鹃觉,比如在請求頭中添加 token 字段盗扇。
  • 響應(yīng)攔截器:該類攔截器的作用是在接收到服務(wù)器響應(yīng)后統(tǒng)一執(zhí)行某些操作沉填,比如發(fā)現(xiàn)響應(yīng)狀態(tài)碼為 401 時(shí),自動(dòng)跳轉(zhuǎn)到登錄頁斑鼻。

定義輔助函數(shù)

generateReqKey:用于根據(jù)當(dāng)前請求的信息猎荠,生成請求 Key;

function generateReqKey(config) {
  const { method, url, params, data } = config;
  return [method, url, Qs.stringify(params), Qs.stringify(data)].join("&");
}

addPendingRequest:用于把當(dāng)前請求信息添加到pendingRequest對象中荒叶;

const pendingRequest = new Map();
function addPendingRequest(config) {
  const requestKey = generateReqKey(config);
  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
    if (!pendingRequest.has(requestKey)) {
       pendingRequest.set(requestKey, cancel);
    }
  });
}

removePendingRequest:檢查是否存在重復(fù)請求些楣,若存在則取消已發(fā)的請求。

function removePendingRequest(config) {
  const requestKey = generateReqKey(config);
  if (pendingRequest.has(requestKey)) {
     const cancelToken = pendingRequest.get(requestKey);
     cancelToken(requestKey);
     pendingRequest.delete(requestKey);
  }
}

設(shè)置請求攔截器

axios.interceptors.request.use(
  function (config) {
    removePendingRequest(config); // 檢查是否存在重復(fù)請求艰猬,若存在則取消已發(fā)的請求
    addPendingRequest(config); // 把當(dāng)前請求信息添加到pendingRequest對象中
    return config;
  },
  (error) => {
     return Promise.reject(error);
  }
);

設(shè)置響應(yīng)攔截器

axios.interceptors.response.use(
  (response) => {
     removePendingRequest(response.config); // 從pendingRequest對象中移除請求
     return response;
   },
   (error) => {
      removePendingRequest(error.config || {}); // 從pendingRequest對象中移除請求
      if (axios.isCancel(error)) {
        console.log("已取消的重復(fù)請求:" + error.message);
      } else {
        // 添加異常處理
      }
      return Promise.reject(error);
   }
);

參考 全棧修仙之路 作者阿寶哥 《 Axios 如何取消重復(fù)請求冠桃?》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末食听,一起剝皮案震驚了整個(gè)濱河市樱报,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌迹蛤,老刑警劉巖襟士,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陋桂,死亡現(xiàn)場離奇詭異,居然都是意外死亡宣渗,警方通過查閱死者的電腦和手機(jī)梨州,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門暴匠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人有序,你說我怎么就攤上這事【ǎ” “怎么了盅称?”我有些...
    開封第一講書人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵缩膝,是天一觀的道長。 經(jīng)常有香客問我将饺,道長痛黎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任掖蛤,我火速辦了婚禮蚓庭,結(jié)果婚禮上仅仆,老公的妹妹穿的比我還像新娘。我一直安慰自己拳魁,他們只是感情好撮弧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開白布贿衍。 她就那樣靜靜地躺著救恨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪擎淤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評(píng)論 1 297
  • 那天桩盲,我揣著相機(jī)與錄音席吴,去河邊找鬼。 笑死柬姚,一個(gè)胖子當(dāng)著我的面吹牛庄涡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播宴合,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼卦洽,長吁一口氣:“原來是場噩夢啊……” “哼斜棚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起弟蚀,我...
    開封第一講書人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬榮一對情侶失蹤昧绣,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后夜畴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體删壮,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡央碟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了苞也。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片粘秆。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡翻擒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陋气,到底是詐尸還是另有隱情,我是刑警寧澤痒玩,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布蠢古,位于F島的核電站别凹,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏炉菲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一嘱丢、第九天 我趴在偏房一處隱蔽的房頂上張望越驻。 院中可真熱鬧道偷,春花似錦、人聲如沸试疙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽距贷。三九已至吻谋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漓拾,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來泰國打工速种, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留配阵,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓棋傍,卻偏偏與公主長得像瘫拣,于是被迫代替她去往敵國和親告喊。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容