tft每日頭條

 > 圖文

 > 封裝的裝怎麼寫

封裝的裝怎麼寫

圖文 更新时间:2024-08-20 18:21:39

本文是我們團隊每周分享的内容,該内容是由導師整理分享的。Eaxios 是我們前端團隊自己在用的庫,由導師封裝的,因為其他小夥伴對它有所好奇,所以才有該篇的分享内容。

正文開始~~

Eaxios

Eaxios 是基于 axios 封裝的網絡請求庫,在保持 API 與 axios 基本一緻的情況下,簡化服務端響應内容和各種異常情況的處理。

開發背景

封裝的裝怎麼寫(我司是怎麼封裝)1

如上圖所示,是一次 Ajax 請求可能輸出的結果,在前端我們需要根據輸出結果給用戶不同的提示。

  • 請求被取消:忽略
  • 網絡異常:提示檢查是否連接網絡
  • 請求超時:提示網絡慢,請切換網絡
  • 服務器異常:提示系統出問題了
  • 響應解析失敗:同上,且可以進行錯誤日志上報
  • 請求失敗:這種情況通常是業務異常,前端需要根據錯誤碼進行相應的處理,最簡單的就是消息提醒
  • 請求成功:前端拿到數據後更新界面

但是,現有的 Axios 庫對于異常結果沒有提供較好的封裝,Axios Promise catch 裡包含各種類型的錯誤,而且沒有提供錯誤碼來識别請求失敗的原因。而且很多服務端接口會返回自己的錯誤碼,這樣在 Axios Promise then 裡也需要處理業務異常。

此外,Axios 本身如下所述的一些問題和局限性。

  • 如果設置 Axios responseType 為 json 時,服務端返回的非 JSON 格式的響應内容會因為無法解析,response.data 為 null對于 500 等錯誤,響應内容會丢失,所以不要去配置 responseType 為 json,對于使用者來說容易采到這個坑。ps:雖然 Axios 官方文檔聲明 responseType 是 json,實際上底層調用 XMLHttpRequest 的 responseType 是沒有傳值的,應該是為了規避這個問題。
  • Axios 默認不管 HTTP 響應狀态和 responseType 是什麼,都會調用默認的 transformResponseps:應該是為了規避上一個問題,默認提供了一個響應處理函數進行 JSON 解析,但是這會影響性能(500 等響應内容值較多時,會造成頁面卡頓)。雖然 transformResponse 可以轉換 response,實際接收到的參數是 response.data,所以無法判斷具體情況來決定是否進行解析 JSON。
  • Axios then 和 catch 是根據 validateStatus 決定的,使用者處理以來較為麻煩。理想情況下,使用者希望 then 返回有效的數據,catch 返回各種錯誤情況:請求被取消、網絡異常、網絡超時、服務端異常、服務端數據格式錯誤、業務異常。
  • Axios 默認不處理 content-type 為 application/x-www-form-urlencoded 類型的請求體,使用起來不夠方便

優化方案:

  • 如果設置 Axios responseType 為 json 時,不要傳給傳 XMLHttpRequest,以避免非 JSON 格式的響應内容丢失
  • Axios 根據響應頭的 content-type 判斷是否需要解析 JSON,以避免性能問題通過請求攔截器實現不給 Axios 傳遞 transformResponse 配置,且将配置備份到其他字段上,然後在響應攔截器中将響應對象 response 傳遞給 transformResponse 處理。響應攔截器根據 response 提供的狀态碼、響應頭和響應内容判斷是否要進行 JSON 轉換。
  • 取消 Axios validateStatus 的配置選項,默認所有大于 0 的狀态碼都是正确的狀态碼,然後在 Axios 攔截器 then 中進行數據解析(非 200 的可能也是 JSON,所以要複用 200 的 JSON 解析代碼),并且根據異常情況抛出直觀的錯誤對象
  • 内置默認處理表單類型的請求體
用法說明

eaxios 主要對響應的處理做了一些優化,除了以下部分,eaxios 的 api 與 axios 保持一緻:

  • eaxios 請求配置的 transformResponse 傳參和處理時機發生了變化axios 在服務端響應内容後就會調用 transformResponse 進行響應轉換,eaxios 響應後内部自動根據響應頭和 responseType 進行 JSON 解析,然後将解析後的數據和 response 傳給 transformResponse,transformResponse 返回的數據最終會被 Promise resovle 給外部調用者。假設服務端返回的數據結構為 { code: 0, message: 'success', data: {} },code 為 0 表示正确的響應,非 0 表示異常,接口請求的代碼示例如下所示:

const eaxios = require('eaxios'); eaxios.defaults.transformResponse = [ function (data, response) { if (typeof data === 'object') { // 默認約定有成功解析 JSON 對象,就認為服務端成功響應,且有提供錯誤碼 if (data.code === 0) { return data.data; } else { throw eaxios.createError(data.message, data.code, response); } } else { // 50x 等服務異常情況 throw eaxios.createError( data, response.config.responseError.SERVER_ERROR, response ); } }, ]; return eaxios('https://run.mocky.io/v3/4f503449-0349-467e-a38a-c804956712b7') .then((data) => { console.log('success', data.id); }) .catch((error) => { console.log('failure', error.code); // UNKNOWN、REQUEST_OFFLINE、REQUEST_TIMEOUT、SERVER_ERROR、RESPONSE_INVALID 和業務錯誤碼 });

ps:如果存在服務單接口請求規範,可以通過 eaxios.create 創建适用于不同接口規範的請求函數。

  • eaxios 的請求處理函數 then 隻會接收到 transformResponse 轉換後的數據,對于網絡、超時、服務端異常和業務異常等問題,會在 catch 接收一個 EaxiosError 類型的錯誤對象。

interface EaxiosError<T = any> extends Error { config: EaxiosRequestConfig; code?: string; request?: any; response?: EaxiosResponse<T>; isAxiosError: boolean; toJSON: () => object; }

錯誤處理函數可以根據錯誤碼 code 來處理異常,code 可能的值為 UNKNOWN、REQUEST_OFFLINE、REQUEST_TIMEOUT、SERVER_ERROR、RESPONSE_INVALID 和其他業務錯誤碼。 ps:如果要定制錯誤碼,可以在請求配置中添加配置項 `responseError`。

eaxios.defaults.responseError = { REQUEST_OFFLINE: '1'REQUEST_OFFLINE };

  • eaxios 内部會自動序列化表單類型的請求參數,所以主要傳對象給 data 就行了。
代碼示例

下面以 { code: 0, message: 'success', data: { } } 這樣的接口規範為例,演示如何使用 eaxios。

const eaxios = require('..'); const request = eaxios.create({ baseURL: 'https://run.mocky.io/v3', timeout: 30000, transformResponse: [ function (data, response) { if (typeof data === 'object') { if (data.code === 0) { return data.data; } else { throw eaxios.createError(data.message, data.code, response); } } else { throw eaxios.createError( data, response.config.responseError.SERVER_ERROR, response, ); } }, ], }); request.interceptors.response.use( function (response) { return response; }, function (error) { if (error && error.code) { if (error.code === 'UNKNOWN') { console.log('未知錯誤'); } else if (error.code === 'REQUEST_OFFLINE') { console.log('網絡未連接'); } else if (error.code === 'REQUEST_TIMEOUT') { console.log('網絡有點慢,請求超時了'); } else if (error.code === 'SERVER_ERROR') { console.log('系統出問題了'); } else if (error.code === 'RESPONSE_INVALID') { console.log('服務端 bug'); } else if (error.code === '10000') { // 假設 10000 為登錄會話過期 console.log('登錄會話失效'); } else { console.log('根據情況是否要消息提示,還是外部處理') } } throw error; }, ); function printError(error) { console.log( `code: ${error.code}, name: ${error.name}, message: ${error.message}, isAxiosError: ${error.isAxiosError}, stack:\n${error.stack}`, ); } function success() { console.log('>> success'); return request('/4f503449-0349-467e-a38a-c804956712b7') .then((data) => { console.log('success', data); }) .catch((error) => { printError(error); }); } function failure() { console.log('>> failure'); return request('/42d7c21d-5ae6-4b52-9c2d-4c3dd221eba4') .then((data) => { console.log('success', data); }) .catch((error) => { printError(error); }); } function invalid() { console.log('>> invalid'); return request('/1b23549f-c918-4362-9ac8-35bc275c09f0') .then((data) => { console.log('success', data); }) .catch((error) => { printError(error); }); } function server_500() { console.log('>> server_500'); return request('/2a9d8c00-9688-4d36-b2de-2dee5e81f5b3') .then((data) => { console.log('success', data); }) .catch((error) => { printError(error); }); } success().then(failure).then(invalid).then(server_500); /* log >> success success { id: 1 } >> failure 登錄會話失效 code: 10000, name: Error, message: error, isAxiosError: true, stack: ... >> invalid 服務端 bug code: RESPONSE_INVALID, name: SyntaxError, message: Unexpected token V in JSON at position 0, isAxiosError: true, stack: ... >> server_500 系統出問題了 code: SERVER_ERROR, name: Error, message: ..., stack: ... */

兼容性

eaxios 依賴 URLSearchParams 處理表單類型的請求參數,不支持的環境需要引入響應的 polyfill

  • core-js

require("core-js/modules/web.url-search-params.js")

  • url-search-params-polyfill
,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关圖文资讯推荐

热门圖文资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved