Axios二次封装最佳实践

Axios二次封装最佳实践

一般自己写 SPA,Axios 基本是首选的 HTTP Library,而对于它的二次封装所谓的“最佳实践”又层出不穷,在这里给一下我的方案吧(其实也是为了方便我自己随时随地 copy)

52字

目标

简单,开箱即用,不用配乱七八糟的文件,最好一个文件完事

TS 项目

type 应该最好还是单独放一个文件吧...? src/service/index.ts

typescript
import type { AxiosError, AxiosInstance } from 'axios'
import type { CustomRequestConfig, IApiResponse } from './types'
import axios from 'axios'

function request<TRequest = any, TResponse = any>(
  config: CustomRequestConfig<TRequest>,
): Promise<TResponse> {
  const instance: AxiosInstance = axios.create({
    baseURL: 'https://api.example.com',
    timeout: 10000,
    headers: { 'Content-Type': 'application/json;charset=UTF-8' },
  })

  instance.interceptors.request.use(
    (config) => {
      const token = localStorage.getItem('token')
      if (token && config.headers) {
        config.headers.Authorization = `Bearer ${token}`
      }
      return config
    },
    (error: AxiosError) => {
      return Promise.reject(error)
    },
  )

  instance.interceptors.response.use(
    (response) => {
      const res = response.data as IApiResponse<TResponse>
      if (res.code !== 0 && res.code !== 200) {
        if (res.code === 401) {
          console.error('Login expired, please log in again!')
        }
        if (config.showError !== false) {
          console.error(res.message || 'Error')
        }
        return Promise.reject(new Error(res.message || 'Error'))
      }
      response.data = res.data
      return response
    },
    (error: AxiosError) => {
      let message = ''
      if (error.response) {
        switch (error.response.status) {
          case 400:
            message = 'Bad Request (400)'
            break
          case 401:
            message = 'Unauthorized, please log in again (401)'
            break
          case 403:
            message = 'Forbidden (403)'
            break
          case 404:
            message = 'Not Found (404)'
            break
          case 500:
            message = 'Internal Server Error (500)'
            break
          default:
            message = `Connection error (${error.response.status})!`
        }
      }
      else if (error.request) {
        message = 'Network connection timeout!'
      }
      else {
        message = 'Request failed, please check your network!'
      }

      if (config.showError !== false) {
        console.error(message)
      }

      return Promise.reject(error)
    },
  )

  return instance.request<any, TResponse>(config)
}

export default request

src/service/types.ts

typescript
import type { AxiosRequestConfig } from 'axios'

export interface CustomRequestConfig<TRequest = any> extends AxiosRequestConfig {
  showLoading?: boolean
  showError?: boolean
  data?: TRequest
}

export interface IApiResponse<T = any> {
  code: number
  message: string
  data: T
}

JS 项目

类型提示用 JSDoc!黑科技

src/service/index.js

javascript
import axios from 'axios'

/**
 * @typedef {import('axios').AxiosRequestConfig & {showError?: boolean, showLoading?: boolean}} CustomRequestConfig
 */

/**
 * General request function based on Axios
 * @param {CustomRequestConfig} config Custom request configuration
 * @returns {Promise<any>} A Promise that resolves with the backend's data field on success, or throws an error on failure
 */
function request(config) {
  const instance = axios.create({
    baseURL: 'https://api.example.com',
    timeout: 10000,
    headers: { 'Content-Type': 'application/json;charset=UTF-8' },
  })

  instance.interceptors.request.use(
    (config) => {
      const token = localStorage.getItem('token')
      if (token && config.headers) {
        config.headers.Authorization = `Bearer ${token}`
      }
      return config
    },
    (error) => {
      return Promise.reject(error)
    },
  )

  instance.interceptors.response.use(
    (response) => {
      const res = response.data

      if (res.code !== 0 && res.code !== 200) {
        if (res.code === 401) {
          console.error('Login expired, please log in again!')
        }

        if (config.showError !== false) {
          console.error(res.message || 'Error')
        }

        return Promise.reject(new Error(res.message || 'Error'))
      }

      return res.data
    },
    (error) => {
      let message = ''
      if (error.response) {
        switch (error.response.status) {
          case 400:
            message = 'Bad Request (400)'
            break
          case 401:
            message = 'Unauthorized, please log in again (401)'
            break
          case 403:
            message = 'Forbidden (403)'
            break
          case 404:
            message = 'Not Found (404)'
            break
          case 500:
            message = 'Internal Server Error (500)'
            break
          default:
            message = `Connection error (${error.response.status})!`
        }
      }
      else if (error.request) {
        message = 'Network connection timeout!'
      }
      else {
        message = 'Request failed, please check your network!'
      }

      if (config.showError !== false) {
        console.error(message)
      }

      return Promise.reject(error)
    },
  )

  return instance.request(config)
}

export default request
评论0