<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【實(shí)戰(zhàn)】Axios 如何實(shí)現(xiàn)請求重試?

          共 7679字,需瀏覽 16分鐘

           ·

          2021-06-22 08:11

          Axios 如何取消重復(fù)請求? 這篇文章中,阿寶哥介紹了在 Axios 中如何取消重復(fù)請求及 CancelToken 的工作原理。而本文將介紹在 Axios 中如何通過 攔截器或適配器 來實(shí)現(xiàn)請求重試的功能。那么為什么要進(jìn)行請求重試呢?這是因?yàn)樵谀承┣闆r下,比如請求超時的時候,我們希望能自動重新發(fā)起請求進(jìn)行重試操作,從而完成對應(yīng)的操作。

          下面阿寶哥將介紹如何使用 Axios 提供的攔截器或適配器來實(shí)現(xiàn)請求重試的功能,如果你對 Axios 的攔截器或適配器還不熟悉的話,建議先閱讀 77.9K 的 Axios 項目有哪些值得借鑒的地方 這篇文章。接下來,我們先來介紹如何使用攔截器實(shí)現(xiàn)請求重試的方案。

          一、攔截器實(shí)現(xiàn)請求重試的方案

          Axios 是一個基于 Promise 的 HTTP 客戶端,而 HTTP 協(xié)議是基于請求和響應(yīng):

          所以 Axios 提供了 請求攔截器和響應(yīng)攔截器 來分別處理請求和響應(yīng),它們的作用如下:

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

          在 Axios 中設(shè)置攔截器很簡單,通過 axios.interceptors.requestaxios.interceptors.response 對象提供的 use 方法,就可以分別設(shè)置請求攔截器和響應(yīng)攔截器:

          export interface AxiosInstance {
            interceptors: {
              request: AxiosInterceptorManager<AxiosRequestConfig>;
              response: AxiosInterceptorManager<AxiosResponse>;
            };
          }

          export interface AxiosInterceptorManager<V> {
            use(onFulfilled?: (value: V) => V | Promise<V>, 
              onRejected?: (error: any) => any): number;
            eject(id: number): void;
          }

          對于請求重試的功能來說,我們希望讓用戶不僅能夠設(shè)置重試次數(shù),而且可以設(shè)置重試延時時間。當(dāng)請求失敗的時候,若該請求的配置對象配置了重試次數(shù),而 Axios 就會重新發(fā)起請求進(jìn)行重試操作。為了能夠全局進(jìn)行請求重試,接下來我們在響應(yīng)攔截器上來實(shí)現(xiàn)請求重試功能,具體代碼如下所示:

          axios.interceptors.response.use(null, (err) => {
            let config = err.config;
            if (!config || !config.retryTimes) return Promise.reject(err);
            const { __retryCount = 0, retryDelay = 300, retryTimes } = config;
            // 在請求對象上設(shè)置重試次數(shù)
            config.__retryCount = __retryCount;
            // 判斷是否超過了重試次數(shù)
            if (__retryCount >= retryTimes) {
              return Promise.reject(err);
            }
            // 增加重試次數(shù)
            config.__retryCount++;
            // 延時處理
            const delay = new Promise((resolve) => {
              setTimeout(() => {
                resolve();
              }, retryDelay);
            });
            // 重新發(fā)起請求
            return delay.then(function ({
              return axios(config);
            });
          });

          以上的代碼并不會復(fù)雜,對應(yīng)的處理流程如下圖所示:

          介紹完如何使用攔截器實(shí)現(xiàn)請求重試的功能之后,下面阿寶哥來介紹適配器實(shí)現(xiàn)請求重試的方案。

          二、適配器實(shí)現(xiàn)請求重試的方案

          Axios 引入了適配器,使得它可以同時支持瀏覽器和 Node.js 環(huán)境。對于瀏覽器環(huán)境來說,它通過封裝 XMLHttpRequest API 來發(fā)送 HTTP 請求,而對于 Node.js 環(huán)境來說,它通過封裝 Node.js 內(nèi)置的 httphttps 模塊來發(fā)送 HTTP 請求。

          Axios 如何緩存請求數(shù)據(jù)? 這篇文章中,阿寶哥介紹了如何通過增強(qiáng)默認(rèn)的 Axios 適配器,來實(shí)現(xiàn)緩存請求數(shù)據(jù)的功能。同樣,采用類似的思路,我們也可以通過增強(qiáng)默認(rèn)的  Axios 適配器來實(shí)現(xiàn)請求重試的功能。

          在介紹如何增強(qiáng)默認(rèn)適配器之前,我們先來看一下 Axios 內(nèi)置的 xhrAdapter 適配器,它被定義在 lib/adapters/xhr.js 文件中:

          // lib/adapters/xhr.js
          module.exports = function xhrAdapter(config{
            return new Promise(function dispatchXhrRequest(resolve, reject{
              var requestData = config.data;
              var requestHeaders = config.headers;

              var request = new XMLHttpRequest();
              // 省略大部分代碼
              var fullPath = buildFullPath(config.baseURL, config.url);
              request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
              // Set the request timeout in MS
              request.timeout = config.timeout;

              // Listen for ready state
              request.onreadystatechange = function handleLoad({ ... }

              // Send the request
              request.send(requestData);
            });
          };

          很明顯 xhrAdapter 適配器是一個函數(shù)對象,它接收一個 config 參數(shù)并返回一個 Promise 對象。而在 xhrAdapter 適配器內(nèi)部,最終會使用 XMLHttpRequest API 來發(fā)送 HTTP 請求。為了實(shí)現(xiàn)請求重試的功能,我們就可以考慮通過高階函數(shù)來增強(qiáng) xhrAdapter 適配器的功能。

          2.1 定義 retryAdapterEnhancer 函數(shù)

          為了讓用戶能夠更靈活地控制請求重試的功能,我們定義了一個 retryAdapterEnhancer 函數(shù),該函數(shù)支持兩個參數(shù):

          • adapter:預(yù)增強(qiáng)的 Axios 適配器對象;
          • options:緩存配置對象,該對象支持  2 個屬性,分別用于配置不同的功能:
            • times:全局設(shè)置請求重試的次數(shù);
            • delay:全局設(shè)置請求延遲的時間,單位是 ms。

          了解完 retryAdapterEnhancer 函數(shù)的參數(shù)之后,我們來看一下該函數(shù)的具體實(shí)現(xiàn):

          function retryAdapterEnhancer(adapter, options{
            const { times = 0, delay = 300 } = options;

            return async (config) => {
              const { retryTimes = times, retryDelay = delay } = config;
              let __retryCount = 0;
              const request = async () => {
                try {
                  return await adapter(config);
                } catch (err) {
                  // 判斷是否進(jìn)行重試
                  if (!retryTimes || __retryCount >= retryTimes) {
                    return Promise.reject(err);
                  }
                  __retryCount++; // 增加重試次數(shù)
                  // 延時處理
                  const delay = new Promise((resolve) => {
                    setTimeout(() => {
                      resolve();
                    }, retryDelay);
                   });
                   // 重新發(fā)起請求
                   return delay.then(() => {
                     return request();
                   });
                  }
                };
             return request();
            };
          }

          以上的代碼并不會復(fù)雜,核心的處理邏輯如下圖所示:

          2.2 使用 retryAdapterEnhancer 函數(shù)

          2.2.1 創(chuàng)建 Axios 對象并配置 adapter 選項
          const http = axios.create({
            baseURL"http://localhost:3000/",
            adapter: retryAdapterEnhancer(axios.defaults.adapter, {
              retryDelay1000,
            }),
          });
          2.2.2 使用 http 對象發(fā)送請求
          // 請求失敗不重試
          function requestWithoutRetry({
            http.get("/users");
          }

          // 請求失敗重試
          function requestWithRetry({
            http.get("/users", { retryTimes2 });
          }

          好了,如何通過增強(qiáng) xhrAdapter 適配器來實(shí)現(xiàn) Axios 請求重試的功能已經(jīng)介紹完了。由于完整的示例代碼內(nèi)容比較多,阿寶哥就不放具體的代碼了。感興趣的小伙伴,可以訪問以下地址瀏覽示例代碼。

          完整的示例代碼:

          https://gist.github.com/semlinker/979ebc659abacea7aa6c0c44af070afe

          這里我們來看一下 Axios 實(shí)現(xiàn)請求重試示例的運(yùn)行結(jié)果:

          三、總結(jié)

          本文介紹了在 Axios 中如何實(shí)現(xiàn)請求重試,基于文中定義的 retryAdapterEnhancer 函數(shù)或響應(yīng)攔截器,你可以輕松地擴(kuò)展請求重試的功能。

          Axios 是一個很優(yōu)秀的開源項目,里面有很多值得我們學(xué)習(xí)與借鑒的地方。如果你對 Axios 內(nèi)部 HTTP 攔截器的設(shè)計與實(shí)現(xiàn)、HTTP 適配器的設(shè)計與實(shí)現(xiàn)及如何防御 CSRF 攻擊感興趣的話,可以閱讀 77.9K 的 Axios 項目有哪些值得借鑒的地方 這篇文章。

          四、參考資源

          瀏覽 46
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  一区二区天堂 | 日本无码无卡二三 | 青娱乐免费视频在线观看 | 怡春院视频 | 婷婷无码成人精品俺来俺去 |