一篇文章讓你看懂封裝Axios

前言

看很多網上的人的封裝 Axios 教程,但或多或少都有不太合適的點,這裡為大傢推薦我的最佳實踐。

攔截器不要返回數據,依然返回 AxiosResponse 對象

網上的文章都讓你用 攔截器 直接返回數據,這種作法其實是非常不妥的,這樣會讓你後續的功能很難進行拓展。

不推薦的做法

import Axios from 'axios'

const client = Axios.create({
  // 你的配置
})

client.interceptors.response.use(response => {
  // 網上的做法都是讓你直接返回數據
  // 這導致後續的一些功能難以支持
  return response.data
})

export default client

推薦的做法

推薦使用函數代替攔截器

import Axios, { AxiosRequestConfig } from 'axios'

const client = Axios.create({
  // 你的配置
})

export async function request(url: string, config?: AxiosRequestConfig) {
  const response = await client.request({ url, ...config })
  const result = response.data
  // 你的業務判斷邏輯
  return result
}

export default client

到這裡可能有人會說太麻煩,請稍等,繼續往下看。

為你的請求添加拓展

很多時候,我們的開發流程是這樣的:

發送請求 => 拿到數據 => 渲染內容

但可惜的是,這隻是理想情況,在某些特殊情況下,你還是需要處理異常或額外的支持,如:

  • 當請求失敗,希望能夠自動重試3次以上再失敗
  • 分頁數據中,當新的請求發出,自動中斷上一次的請求
  • 第三方提供 jsonp 接口,而你又隻能使用靜態頁時 (ps: Axios 不支持 jsonp)
  • 更多

當發送以上場景時,你隻能默默的寫代碼支持,但如果你不攔截 Axios 的響應,那就可以使用開源社區提供的方案。

支持請求重試

安裝 axios-retry,可以讓你的 Axios 支持自動重試的功能

import Axios, { AxiosRequestConfig } from 'axios'
import axiosRetry from 'axios-retry'

const client = Axios.create({
  // 你的配置
})

// 安裝 retry 插件
// 當請求失敗後,自動重新請求,隻有3次失敗後才真正失敗
axiosRetry(client, { retries: 3 })

export async function request(url: string, config?: AxiosRequestConfig) {
  const response = await client.request({ url, ...config })
  const result = response.data
  // 你的業務判斷邏輯
  return result
}

// 隻有3次失敗後才真正失敗
const data = request('http://example.com/test')

PS: axios-retry 插件支持配置單個請求

支持 jsonp 請求

安裝 axios-jsonp,可以讓你的 Axios 支持 jsonp 的功能。

import Axios, { AxiosRequestConfig } from 'axios'
import jsonpAdapter from 'axios-jsonp'

const client = Axios.create({
  // 你的配置
})

export async function request(url: string, config?: AxiosRequestConfig) {
  const response = await client.request({ url, ...config })
  const result = response.data
  // 你的業務判斷邏輯
  return result
}

export function jsonp(url: string, config?: AxiosRequestConfig) {
  return request(url, { ...config, adapter: jsonpAdapter })
}

// 你現在可以發送 jsonp 的請求瞭
const data = jsonp('http://example.com/test-jsonp')

支持 URI 版本控制

有開發 Web API 經驗的人都會遇到一個問題,如果 API 出現重大變更的時候,如何保證舊版可用的情況下,發佈新的 API?

這種情況在服務端開發場景中,其實並不罕見,尤其是對外公開的 API,如: 豆瓣 API (已失效)。

當前主流的支持 3 種類型的版本控制:

類型 描述
URI Versioning 版本將在請求的 URI 中傳遞(默認)
Header Versioning 自定義請求標頭將指定版本
Media Type Versioning Accept 請求的標頭將指定版本

URI 版本控制 是指在請求的 URI 中傳遞的版本,例如 https://example.com/v1/routehttps://example.com/v2/route

import Axios, { AxiosRequestConfig } from 'axios'

const client = Axios.create({
  // 你的配置
})

client.interceptors.request.use(config => {
  // 最簡單的方案
  config.url = config.url.replace('{version}', 'v1')
  return config
})

// GET /api/v1/users
request('/api/{version}/users')

Header 和 Media Type 模式,可以參考如下文章來實現

  • 實現 Web API Versioning 功能
  • nest versioning

保持請求唯一

在一個支持翻頁的後臺表格頁,一個用戶擊翻頁按鈕,請求發出等待響應,但用戶這時點擊搜索,需要重新獲取數據,支持你的情況可能是:

  • 翻頁請求先回,搜索數據再回,數據顯示正常
  • 搜索數據先回,翻頁數據再回,數據顯示異常(通常在負載均衡的場景中出現)

為此,你希望能夠自動取消上一次請求,於是你看瞭 Axios 的取消請求,但好多地方都需要用到,於是可以將這個功能封裝成獨立的函數。

import Axios from 'axios'

const CancelToken = Axios.CancelToken

export function withCancelToken(fetcher) {
  let abort

  function send(data, config) {
    cancel() // 主動取消

    const cancelToken = new CancelToken(cancel => (abort = cancel))
    return fetcher(data, { ...config, cancelToken })
  }

  function cancel(message = 'abort') {
    if (abort) {
      abort(message)
      abort = null
    }
  }

  return [send, cancel]
}

使用

function getUser(id: string, config?: AxiosRequestConfig) {
  return request(`api/user/${id}`, config)
}

// 包裝請求函數
const [fetchUser, abortRequest] = withCancelToken(getUser)

// 發送請求
// 如果上一次請求還沒回來,會被自動取消
fetchUser('1000')

// 通常不需要主動調用
// 但可以在組件銷毀的生命周期中調用
abortRequest()

這樣不需要自動取消的時候,直接使用原函數即可,也不會影響原函數的使用

後語

Axios 封裝其實還有很多事情可以做,比如 全局錯誤處理 (一樣不能影響正常請求) 等,封裝也不應該隻是利用攔截器直接返回數據。

另外請求模塊應該保持獨立,推薦拓展 AxiosRequestConfig 或做成一個個獨立的函數,提供給外部調用,方便做成一個獨立的 HTTP 模塊。

總結

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

推薦閱讀: