在項目中封裝axios的實戰過程

前言

在學習和做項目的時候經常會碰到axios,之前做的項目一般都是配置好axios,所以自己一直有個大概印象,最近有個機會自己可以手動配置axios,順便記錄分享一下~

axios封裝的好處

axios封裝的好處是統一處理,提高效率,便於維護。

你可以像下面一樣這麼使用axios請求接口

axios.get('http://localhost:10086/user?ID=12345')
  .then(response => {
    //成功後的操作...
  })
  .catch(error => {
    //失敗後的操作...
  });

但是當接口請求多起來,需求多起來的時候,在項目中每個需要接口請求的地方寫一遍這樣的代碼,這樣就會產生很多重復性的代碼,降低我們的開發效率和提高維護成本。

封裝思路

我們需要一次性集中配置axios,讓配置適應我們項目的大部分場景。我們可以新建一個js文件,使用自定義配置新建一個 axios 實例,然後對實例進行基本配置,在請求前(請求體處理),請求後(返回的結果處理)等這些階段添加一些我們需要的處理,然後將其導出使用。

配置的優先順序

配置會以一個優先順序進行合並。這個順序是:在 lib/defaults.js 找到的庫的默認值,然後是實例的 defaults 屬性,最後是請求的 config 參數。(這樣有些特殊的場景我們也可以單獨處理)

node_modules文件夾下axios庫文件下的lib/defaults.js。

自定義實例默認值

const instance = axios.create({
  baseURL: 'https://api.example.com'
});

請求的config參數

axios({   
method:'get',   
url:'http://bit.ly/2mTM3nY',   
responseType:'stream' }).then(function(response) {   response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) });

axios實例配置

1、定義一些常規的配置

設置BaseUrl

baseUrl一般有分為生產、開發、測試等多個地址,我們可以弄一個config.js進行存放,如果是vue或react我們可以新建env等文件進行存放,下面的baseUrl是使用react的環境變量的。

  • 設置timeout請求超時的時間
  • 設置數據請求的格式Content-Type(有 application/x-www-form-urlencoded、multipart/form-data、application/json…)等等
import axios from 'axios'

export const request = createAxiosInstance()

function createAxiosInstance () {
  const instance = axios.create({
    baseURL: process.env.REACT_APP_BASE_URL,
    timeout: 5000,
    headers: {
      // 可定義統一的請求頭部
      post: {
        'Content-Type': 'application/json'
      }
      ...
    }
  })
  return instance
}

2、請求前加一些我們需要的操作,

比如需要在請求頭裡添加token

請求參數判空處理

(下圖的例子傳瞭空的name和personId,這種會引起歧義,究竟是要獲取參數值為空還是忽略這些參數呢,有一些後端會進行一些處理,但前端還是盡量避免~)

每次接口請求時開啟loading動畫效果等等

  // 添加請求攔截器(在發送請求之前做些什麼)
  instance.interceptors.request.use((config) => {
      //可添加開啟loading效果的函數
      loading.open()  
      //token 存在就添加到請求頭裡
      token && (config.headers.Authorization = token)
     // 過濾請求參數中的 null undefined ''的函數
      cleanObject()
      return config
  })

3、請求返回後,添加攔截操作,

  • 處理成功返回的數據

比如後端返回的data數據可能嵌套瞭很多層,你可以直接返回你需要的data數據,這樣業務代碼就可以直接拿到最終的數據,而不用每次去解構之類的。

  • 統一處理失敗後的異常報錯

接口請求有成功也有失敗,如果你不想在每寫一個接口請求的時候都需要去寫一遍失敗的邏輯代碼,並且幾乎都是重復的時候,那你可以在這裡集中進行接口的統一的異常處理。如判斷狀態碼或後端自定義的code,並把後端返回的錯誤提示顯示出來。

 // 添加響應攔截器(對響應數據做點什麼)
  instance.interceptors.response.use((response) => {
   //可添加關閉loading效果的函數
      loading.close()  
      //解構出返回結果的數據
      const res = response.data
      //對自定義code碼進行判斷,將成功的數據返回出去
      const validateStatus = /^(2|3)\d{2}$/ //code為2或3開頭的視作請求成功
      if (validateStatus.test(res.code)) {
        return res      //直接return出去我們需要的data
      }
      //判斷失敗的code碼並作出提示等操作
      if (res.code === 401) {
        message.error(res.msg)
      } else {
        message.warning(res.msg)
      }
      return Promise.reject(res)
      },
      (error) => {
      loading.close() 
      if (error.response.status === 401) {
        message.error('token失效,請重新登錄!')
        removeStorageToken()
        setTimeout(() => {
          window.location.href = '/login'
        }, 2000)
      } else {
        if (!window.navigator.onLine) {
          message.warning('網絡異常,請檢查網絡是否正常連接')
        } else if (error.code === 'ECONNABORTED') {
          message.warning('請求超時')
        } else {
          message.warning('服務器異常,請聯系管理員')
        }
      }
      return Promise.reject(error) // 將錯誤繼續返回給到具體頁面
    }
      )

上面有根據HTTP狀態碼和自定義code做的一些錯誤處理,這裡進行瞭錯誤攔截後,頁面進行業務接口調用的時候就不用再每次進行錯誤提示處理。當然要根據不同項目需求進行配置。

請求接口方法統一管理

一般我們會把所有的接口請求方法寫在一起進行統一管理,後期更改的時候也方便查找維護。

我們可以新建一個管理api請求的文件夾(如apiList),裡面放我們各種請求文件(這裡按功能分)。如user.js就存放用戶相關的請求,其他類推。然後頁面就可以直接引用方法進行接口調用。

import { request } from '../axios'

// 獲取用戶信息
export function getUserInfo (userId) {
  return request.get(`/sys/user/info/${userId}`)
}

在組件或頁面直接調用方法就可以瞭~

最後放一下完整的示例!大傢可以參考一下~

這個示例配置適用於vue或react,當然每個項目的配置都會有些不同,小夥伴要根據自己項目進行修改配置和擴充~

import axios from 'axios'

export const request = createAxiosInstance()

function createAxiosInstance () {
  const instance = axios.create({
    baseURL: process.env.REACT_APP_BASE_URL,
    timeout: 5000,
    headers: {
      // 可定義統一的請求頭部
      post: {
        'Content-Type': 'application/json'
      }
      ...
    }
  })
   // 添加請求攔截器(在發送請求之前做些什麼)
  instance.interceptors.request.use((config) => {
      //可添加開啟loading效果的函數
      loading.open()  
      //token 存在就添加到請求頭裡
      token && (config.headers.Authorization = token)
     // 過濾請求參數中的 null undefined ''的函數
      cleanObject()
      return config
  })
  // 添加響應攔截器(對響應數據做點什麼)
  instance.interceptors.response.use((response) => {
   //可添加關閉loading效果的函數
      loading.close()  
      //解構出返回結果的數據
      const res = response.data
      //對自定義code碼進行判斷,將成功的數據返回出去
      const validateStatus = /^(2|3)\d{2}$/ //code為2或3開頭的視作請求成功
      if (validateStatus.test(res.code)) {
        return res
      }
      //判斷失敗的code碼並作出提示等操作
      if (res.code === 401) {
        message.error(res.msg)
      } else {
        message.warning(res.msg)
      }
      return Promise.reject(res)
      },
      (error) => {
      loading.close()  //可添加關閉loading效果的函數
      if (error.response.status === 401) {
        message.error('token失效,請重新登錄!')
        removeStorageToken()
        setTimeout(() => {
          window.location.href = '/login'
        }, 2000)
      } else {
        if (!window.navigator.onLine) {
          message.warning('網絡異常,請檢查網絡是否正常連接')
        } else if (error.code === 'ECONNABORTED') {
          message.warning('請求超時')
        } else {
          message.warning('服務器異常,請聯系管理員')
        }
      }
      return Promise.reject(error) // 將錯誤繼續返回給到具體頁面
    }
      )
  
  return instance
}

總結

到此這篇關於在項目中封裝axios的文章就介紹到這瞭,更多相關項目中封裝axios內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: