最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解axios是如何處理異常的

 更新時間:2024年05月20日 08:42:54   作者:zhangbao90s  
本文我們將討論?axios?中是如何處理異常的,在此之前,我們先了解以下?axios?中各種類型的異常,文中通過代碼示例講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下

axios 中的正常請求

axios 中當請求服務正常返回時,會落入 .then() 方法中。

axios.get('https://httpstat.us/200')
  .then(res => {
    console.log(res)
  })

效果如下:

axios 會把響應結果包裝在返回的 Response 對象的 data 屬性中,除此之外:

  • config:即請求配置
  • headers:響應頭數(shù)據(jù)(AxiosHeaders 對象)
  • request:請求實例。瀏覽器環(huán)境就是 XMLHttpRequest 對象
  • status:HTTP 狀態(tài)碼。本案例是 200,表示請求成功處理了
  • statusText: 狀態(tài)碼的文字說明

axios 中的異常請求

axios 中的異常請求分 2 類:有響應異常請求和無響應的異常請求。

有響應的異常

當返回的 HTTP 狀態(tài)碼是 2xx 之外的是狗,就會進入 axios 的 .catch() 方法中。

403 響應:

axios.get('https://httpstat.us/403')
  .catch(err => {
    console.log(err)
  })

效果:

500 響應:

axios.get('https://httpstat.us/500')
  .catch(err => {
    console.log(err)
  })

效果:

以上 2 個場景,返回的都是一個 AxiosError 對象,它繼承自 Error。相比 Error,AxiosError 除了常規(guī)的 code、message、name 和 stack 屬性(非標準)外,還包含 config、request 和 reponse:

  • response 就是響應對象,與正常請求時返回的響應對象完全一致
  • config 和 request 與 Response 對象里的一樣——前者是請求配置,后者則是底層的請求對象

自定義 validateStatus()

當然,對于有響應的請求,2xx 狀態(tài)碼進入 then,之外的狀態(tài)碼進入 catch 是 axios 的默認配置——通過 validateStatus() 設置的。

// `validateStatus` defines whether to resolve or reject the promise for a given
// HTTP response status code. If `validateStatus` returns `true` (or is set to `null`
// or `undefined`), the promise will be resolved; otherwise, the promise will be
// rejected.
validateStatus: function (status) {
  return status >= 200 && status < 300; // default
},

在 axios 內(nèi)部,當接收到響應后,會將響應碼傳入 validateStatus() 函數(shù)校驗。返回 true,就表示請求成功,否則表示請求失敗。

你可以自由調整這里的判斷,決定哪類響應可以作為成功的請求處理。

比如,將返回狀態(tài)碼 4xx 的請求也看做是成功的。

axios.get('https://httpstat.us/404', {
  validateStatus: function (status) {
    return status < 500; // Resolve only if the status code is less than 500
  }
})
  .then(res => {
    console.log(res)
  })

效果:

我們設置可以將 validateStatus 設置為 null,將所有有響應返回的請求都看作是成功的,這樣也能進入 .then() 中處理了。

axios.get('https://httpstat.us/500', {
  validateStatus: null
})
  .then(res => {
    console.log(res)
  })

效果:

無響應的異常

不過某些請求是沒有響應返回的。比如:網(wǎng)絡中斷、跨域錯誤、超時、取消請求等。這類異常請求都沒有響應返回,但都會落入到 .catch() 里。

網(wǎng)絡中斷

先以網(wǎng)絡中斷的情況舉例。

axios.get('https://httpstat.us/200?sleep=10000', {
})
  .catch(err => {
    console.log(err)
  })

我們模擬了一個耗時 10s 的請求,在此期間,我們將電腦的網(wǎng)絡斷掉。就能看到效果。

這個時候可以發(fā)現(xiàn),catch() 中接收到 Axios 對象是沒有 response 屬性的,說明沒有服務響應。同時,錯誤信息是“Network Error”,也就是網(wǎng)絡服務。

當然,無效地址以及跨域錯誤,也報錯 “Network Error”。

超時報錯

再演示一個請求超時的案例。

axios.get('https://httpstat.us/200?sleep=10000', {
  timeout: 1000
})
  .catch(err => {
    console.log(err)
  })

我們模擬了個 10s 返回的請求,而超時限制設置在了 1s。運行代碼,效果如下:

顯而易見,錯誤里依然沒有 response 屬性,錯誤的消息也很清晰的說明了問題:"過了 1s 的超時限制了"。

取消請求

axios 中還提供了取消請求的方案。

const controller = new AbortController();

axios.get('https://httpstat.us/200?sleep=10000', {
  signal: controller.signal
})
  .catch(err => {
    console.log(err)
  })

controller.abort();

效果如下:

catch() 捕獲到的是一個 CanceledError 對象,它繼承了 AxiosError,這樣我們就能單獨判斷這類自動取消的情況了。注意,這里依然是沒有 response 屬性的。

當然,axios 中還有一個舊的取消方案——使用 CancelToken。

axios.get('https://httpstat.us/200?sleep=10000', {
  cancelToken: source.token
})
  .catch(res => {
    console.log(res)
  })

source.cancel();

相比較于 AbortController 觸發(fā)的取消,少了 config 和 request 屬性。

以上,我們就列完了 aioxs 中各類異常請求的場景及表現(xiàn)。官方倉庫 README 的 Handling Errors 也對此做了歸納。

axios.get('/user/12345')
  .catch(function (error) {
    if (error.response) {
      // 請求發(fā)出,并且得到服務器響應
      // 響應碼在 2xx 之外(默認)
      console.log(error.response.data);
      console.log(error.response.status);
      console.log(error.response.headers);
    } else if (error.request) {
      // 請求發(fā)出,但沒有響應返回
      // `error.request` 對應底層請求對象。瀏覽器環(huán)境是 XMLHttpRequest 實例,Node.js 環(huán)境下則是 http.ClientRequest 實例
      console.log(error.request);
    } else {
      // 在請求準備/響應處理階段出錯了
      console.log('Error', error.message);
    }
    console.log(error.config);
  });

接下來就來分析 axios 中是如何實現(xiàn)請求的異常處理的。

源碼分析

我們還是以 axios 的瀏覽器端實現(xiàn)(lib/adapters/xhr.js)為例。

AxiosError

通過前面的學習,我們知道 axios 拋出的異常是基于 Error 基類封裝的 AxiosError,其源代碼位于 /lib/core/AxiosError.js。

function AxiosError(message, code, config, request, response) {
  // 1)
  Error.call(this);
  // 2)
  if (Error.captureStackTrace) {
    Error.captureStackTrace(this, this.constructor);
  } else {
    this.stack = (new Error()).stack;
  }
  // 3)
  this.message = message;
  this.name = 'AxiosError';
  // 4)
  code && (this.code = code);
  config && (this.config = config);
  request && (this.request = request);
  response && (this.response = response);
}

簡單做一些說明:

  • Error.call(this) 的作用類似調用父級構造函數(shù),AxiosError 實例原型也成 Error 實例了
  • 收集報錯棧信息,優(yōu)先以 Error.captureStackTrace 方式收集,方便排查問題
  • 設置常規(guī)屬性 message 和 name
  • 擴展出 code、code、code 和 response,這些都是可選的

當然 AxiosError 還有其他代碼,因為本文不涉及,就不再贅述。

介紹完 AxiosError,就可以分析 axios 中是如何拋出 AxiosError 的了。

XMLHttpRequest 對象

在能夠拋出異常之前,我們需要先創(chuàng)建請求對象 request。

// https://github.com/axios/axios/blob/v1.6.8/lib/adapters/xhr.js#L76
let request = new XMLHttpRequest();

瀏覽器環(huán)境,request 就是 XMLHttpRequest 實例,接下來的異常處理都是基于 request 上的監(jiān)聽事件捕獲的。

無響應異常的處理

接下來,我們先講無響應異常的處理,因為它們的相對邏輯比較簡單。

網(wǎng)絡異常

這類異常包括:網(wǎng)絡中斷、跨域錯誤以及請求地址錯誤。通過監(jiān)聽 request 的 onerror 事件實現(xiàn):

// /v1.6.8/lib/adapters/xhr.js#L158-L166
// Handle low level network errors
request.onerror = function handleError() {
  // Real errors are hidden from us by the browser
  // onerror should only fire if it's a network error
  reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request));

  // Clean up request
  request = null;
};

直接返回了一個 reject 狀態(tài)的 Promise,表示請求失敗。并返回了 CODE 值為 ERR_NETWORK 的 AxiosError 對象。

超時處理

再來看看對超時的處理,監(jiān)聽了 ontimeout 事件。

// /v1.6.8/lib/adapters/xhr.js#L168-L183
// Handle timeout
request.ontimeout = function handleTimeout() {
  let timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';
  const transitional = config.transitional || transitionalDefaults;
  if (config.timeoutErrorMessage) {
    timeoutErrorMessage = config.timeoutErrorMessage;
  }
  reject(new AxiosError(
    timeoutErrorMessage,
    transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED,
    config,
    request));

  // Clean up request
  request = null;
};

處理也很簡單,同樣是 reject Promise,同時拋出一個 CODE 值為 ECONNABORTED 的 AxiosError 對象。

transitional 配置對象是為了向后兼容才保留的,已不再推薦使用,所以你可以忽略這部分你的判斷邏輯。

另外,你還可以通過傳入 config.timeoutErrorMessage 配置,自定義超時報錯消息。

取消請求

取消請求依賴的是監(jiān)聽 onabort 事件。

// /v1.6.8/lib/adapters/xhr.js#L146-L156
// Handle browser request cancellation (as opposed to a manual cancellation)
request.onabort = function handleAbort() {
  if (!request) {
    return;
  }

  reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request));

  // Clean up request
  request = null;
};

當你調用 request 上的 abort() 方法時,就會觸發(fā)這個事件調用。

在 axios 內(nèi)部,不管你是通過 signal 還是通過 cancelToken(已棄用),內(nèi)部都是通過調用 request.abort() 來中止請求的。

取消請求的報錯 CODE 值跟超時一樣也是 ECONNABORTED,不過報錯消息是“Request aborted”。這樣你就能區(qū)分這次請求是瀏覽器取消的還是人工取消的了。

// /v1.6.8/lib/adapters/xhr.js#L231-L247
if (config.cancelToken || config.signal) {
  // Handle cancellation
  // eslint-disable-next-line func-names
  onCanceled = cancel => {
    if (!request) {
      return;
    }
    reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel);
    request.abort();
    request = null;
  };

  config.cancelToken && config.cancelToken.subscribe(onCanceled);
  if (config.signal) {
    config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);
  }
}

再來看看,有響應的異常處理邏輯。

有響應異常的處理

axios 內(nèi)部通過監(jiān)聽 onloadend 事件來處理有響應的異常請求。

// /v1.6.8/lib/adapters/xhr.js#L125
request.onloadend = onloadend

不管當前請求是否成功,onloadend 回調總是會調用,這里其實是可以使用 onload 事件替代的。

request.onload = onloadend

之所以有這部分邏輯是為了向后兼容,因為 axios 中這部分的完整邏輯是這樣的。

if ('onloadend' in request) {
  // Use onloadend if available
  request.onloadend = onloadend;
} else {
  // Listen for ready state to emulate onloadend
  request.onreadystatechange = function handleLoad() {
    // ...
    
    // readystate handler is calling before onerror or ontimeout handlers,
    // so we should call onloadend on the next 'tick'
    setTimeout(onloadend);
  }
}

OK,我們繼續(xù)看 onloadend 函數(shù)的內(nèi)容:

// /v1.6.8/lib/adapters/xhr.js#L92-L121
function onloadend() {
  // 1)
  if (!request) {
    return;
  }
  
  // 2)
  // Prepare the response
  const responseHeaders = AxiosHeaders.from(
    'getAllResponseHeaders' in request && request.getAllResponseHeaders()
  );
  const responseData = !responseType || responseType === 'text' || responseType === 'json' ?
    request.responseText : request.response;
  const response = {
    data: responseData,
    status: request.status,
    statusText: request.statusText,
    headers: responseHeaders,
    config,
    request
  };
  
  // 3)
  settle(function _resolve(value) {
    resolve(value);
    done();
  }, function _reject(err) {
    reject(err);
    done();
  }, response);
  
  // Clean up request
  request = null;
}
  • 這里做了 request 的非空判斷。因為 onloadend 在調用之前,可以已經(jīng)在其他的回調事件中處理了,直接返回即可
  • 這里則是準備返回的響應數(shù)據(jù)。先收集響應頭數(shù)據(jù),再獲得響應數(shù)據(jù),最后拼成 Respoonse 對象返回。注意,當 responseType 是 "json" 時,響應數(shù)據(jù)返回的是 request.responseText,是個字符串,這會在下一步處理。
  • 這里我們將拼接的 response 交由 settle 函數(shù)處理,并由它決定最終是成功請求(resolve(err))還是失敗請求(reject(err)

settle 函數(shù)位于 lib/core/settle.js:

/**
 * Resolve or reject a Promise based on response status.
 *
 * @param {Function} resolve A function that resolves the promise.
 * @param {Function} reject A function that rejects the promise.
 * @param {object} response The response.
 *
 * @returns {object} The response.
 */
export default function settle(resolve, reject, response) {
  // 1)
  const validateStatus = response.config.validateStatus;
  // 2)
  if (!response.status || !validateStatus || validateStatus(response.status)) {
    resolve(response);
  // 3)
  } else {
    reject(new AxiosError(
      'Request failed with status code ' + response.status,
      [AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],
      response.config,
      response.request,
      response
    ));
  }
}
  • 我們首先拿到了 validateStatus 配置。這是我們判斷請求成功與否的關鍵
  • 這個 if 通過就把傳入的 response 直接丟出去,表示請求成功了。跟這個判斷邏輯,我們可以知道,當 validateStatus 為空(nullundefined),所有響應都會認為是成功的被返回
  • 否則,沒有通過校驗那就表示請求失敗了。報錯消息類似 'Request failed with status code xxx';4xx 狀態(tài)碼的返回 CODE 是 ERR_BAD_REQUEST,5xx 狀態(tài)碼的返回 CODE 是 ERR_BAD_RESPONSE;最后我們還把 response 作為 AxiosError 的 response 屬性傳入了進來

至此,我們就講完了 axios 中的異常處理邏輯了。

總結

本文介紹了 axios 請求過程中可能會出現(xiàn)的各種異常場景。

axios 異常場景按照有無響應分 2 類:有響應異常和無響應異常。有響應異常就是指那些能成功接收到服務器響應狀態(tài)碼的請求,包括常見的 2xx、4xx 和 5xx;無響應異常則包括網(wǎng)絡中斷、無效地址、跨域錯誤、超時、取消等場景下的錯誤,這些都是接受不到服務器響應的。

然后,我們從瀏覽器端實現(xiàn)出發(fā),介紹了 AxiosError、分析了拋出 AxiosError 異常的時機與方式。

以上就是詳解axios是如何處理異常的的詳細內(nèi)容,更多關于axios處理異常的資料請關注腳本之家其它相關文章!

相關文章

  • JS ES6展開運算符的幾個妙用

    JS ES6展開運算符的幾個妙用

    這篇文章主要介紹了JS ES6展開運算符的幾個妙用,想了解ES6的同學,可以參考下
    2021-04-04
  • JS實現(xiàn)可針對算術表達式求值的計算器功能示例

    JS實現(xiàn)可針對算術表達式求值的計算器功能示例

    這篇文章主要介紹了JS實現(xiàn)可針對算術表達式求值的計算器功能,可實現(xiàn)基本的數(shù)字四則運算功能,涉及javascript基本數(shù)值運算與流程控制、判斷等操作技巧,需要的朋友可以參考下
    2018-09-09
  • webpack+vue2構建vue項目骨架的方法

    webpack+vue2構建vue項目骨架的方法

    本篇文章主要介紹了webpack+vue2構建vue項目骨架的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-01-01
  • 微信小程序全屏滾動字幕的實現(xiàn)方法詳解

    微信小程序全屏滾動字幕的實現(xiàn)方法詳解

    這篇文章主要介紹了微信小程序全屏滾動字幕的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08
  • 圖文詳解JavaScript的原型對象及原型鏈

    圖文詳解JavaScript的原型對象及原型鏈

    許多人對JavaScript的原型及原型鏈仍感到困惑,網(wǎng)上的文章又大多長篇大論,令讀者不明覺厲。下面小編將用最簡潔明了的圖文介紹JavaScript的原型及原型鏈。
    2016-08-08
  • 前端無感知刷新token以及超時自動退出實現(xiàn)方案

    前端無感知刷新token以及超時自動退出實現(xiàn)方案

    前端需要做到無感刷新token,即刷token時要做到用戶無感知,避免頻繁登錄,下面這篇文章主要給大家介紹了關于前端無感知刷新token以及超時自動退出的實現(xiàn)方案,需要的朋友可以參考下
    2024-01-01
  • Apply an AutoFormat to an Excel Spreadsheet

    Apply an AutoFormat to an Excel Spreadsheet

    Apply an AutoFormat to an Excel Spreadsheet...
    2007-06-06
  • JS對象類型之Error錯誤對象的用法詳解

    JS對象類型之Error錯誤對象的用法詳解

    error對象是JavaScript的原生對象,當程序解析和運行過程中發(fā)生了錯誤,JS引擎就會自動產(chǎn)生并拋出一個error對象的實例,并且程序會終止在錯誤發(fā)生的地方,本文給大家介紹了JS Error錯誤對象的用法,需要的朋友可以參考下
    2024-04-04
  • 微信小程序實現(xiàn)圖片懶加載的示例代碼

    微信小程序實現(xiàn)圖片懶加載的示例代碼

    本篇文章主要介紹了微信小程序實現(xiàn)圖片懶加載的示例代碼,實現(xiàn)的原理是通過頁面預加載圖片,對用戶體驗度會有一定的提高,具有一定的參考價值,有興趣可以了解一下
    2017-12-12
  • 新手快速入門JavaScript裝飾者模式與AOP

    新手快速入門JavaScript裝飾者模式與AOP

    這篇文章主要介紹了新手快速入門JavaScript裝飾者模式與AOP,在不改變對象)的情況下動態(tài)的為其添加功能,這就是裝飾者模式,下面小編帶大家來深入學習一下吧
    2019-06-06

最新評論

米易县| 当阳市| 达日县| 鲜城| 岳池县| 资溪县| 莱州市| 区。| 嵊泗县| 昔阳县| 泉州市| 清苑县| 广饶县| 麻城市| 自贡市| 霍山县| 庐江县| 青田县| 大兴区| 久治县| 绥阳县| 南昌市| 华池县| 桃园市| 长宁区| 高州市| 娱乐| 托克托县| 钟山县| 营口市| 夏河县| 桂平市| 灌南县| 南皮县| 茂名市| 息烽县| 曲沃县| 竹溪县| 香格里拉县| 革吉县| 栾城县|