axios封装

axios的封装基于vite

什么是 Axios?


What is Axios?

Axios 是一个 基于 promise 的 HTTP 客户端,适用于 node.js 和浏览器。它提供了简洁的API、自动JSON数据转换、请求/响应拦截等强大功能。

一、安装

  • 使用 npm: npm install axios
  • 使用 yarn: yarn add axios

并在src文件夹下创建文件

二、创建Axios实例

在request文件下创建axios实例

javascript 复制代码
import axios from 'axios'

const base = import.meta.env.VITE_APP_API // 接口地址

const service= axios.create({
  baseURL: base,
  timeout: 60000, // 设置超时时间 
})

这里需要注意两点

  1. 需要在项目根目录下配置env环境文件

    在vite中需要这样配置
    必须使用VITE开头的配置信息 否则无法获取
javascript 复制代码
NODE_ENV = "dev"
VITE_APP_ENV='dev'

//开发环境后端接口地址
VITE_APP_API='http://www.dev.com'
  1. 在package.json配置与env名字一样,来区分启动环境
javascript 复制代码
    "dev": "vite --mode dev",
    "test": "vite build --mode test",
    "build": "vite build --mode prod",

三、封装请求拦截request

3.1 统一设置token

javascript 复制代码
service.interceptors.request.use(
  (config: any) => {
    // Do something before request is sent
    const token = localStorage.getItem('access_token')
    config.headers['X-Token'] = `Bearer ${token}` // 设置token

    return config
  },
  (error) => {
    // Do something with request error
    return Promise.reject(error)
  },
)

3.2 处理无需token情况

javascript 复制代码
service.interceptors.request.use(
  (config: any) => {
    // Do something before request is sent
    const needToken = !(config.params?.noToken || config.data?.noToken)
    
    // 示例1:添加token
    const token = localStorage.getItem('access_token')
    if (needToken) {
      config.headers['X-Token'] = `Bearer ${token}` // 设置token
    }
 
    delete config.params.noToken 

    return config
  },

使用方法

javascript 复制代码
    let params = {
        noToken: true, 
    }
    const res = await getXXX(params)

3.3 动态处理FormData格式(比如文件上传)

javascript 复制代码
   if (config.data instanceof FormData) {
      config.headers['Content-Type'] = 'multipart/form-data' // 文件上传
    }

3.4 请求重试

javascript 复制代码
const RETRY_COUNT = 3
let retry = 0 // 重试次数

service.interceptors.request.use(
  (config: any) => {
    // Do something before request is sent
    config.metaData = { startTime: Date.now() }
    return config
  },
  (error) => {
    // Do something with request error
    if (retry < RETRY_COUNT) {
      retry++
      console.warn(`请求超时,正在进行第 ${retry} 次重试...`)
      return service.request(error.config)
    }
    return Promise.reject(error)
  },
)

响应拦截里面

javascript 复制代码
service.interceptors.response.use(
  (response: any) => { 
    const endTime = Date.now()
    const duration = endTime - response.config.metaData.startTime
    console.log(`请求 ${response.config.url} 耗时 ${duration}ms`)
)

3.5 取消重复请求

应用条件:在某些情况下(例如网络连接不可用),尽早取消连接将使 axios 调用受益。如果不取消,axios 调用可能会挂起,直到父代码/堆栈超时(在服务器端应用中可能是几分钟)。

由于cancelToken 官网已经弃用这里就不再使用了,这里使用的是signal 这个方法。

在request文件下添加官网的这段代码

bash 复制代码
	function newAbortSignal(timeoutMs: number) { 
	  const abortController = new AbortController()
	  setTimeout(() => abortController.abort(), timeoutMs || 0)
	
	  return abortController.signal
	}

在请求拦截里面设置

bash 复制代码
    config.signal = newAbortSignal(config.timeout || 60000) //  超时控制
    delete config.params.signal //删除请求参数

在http文件中设置

bash 复制代码
	.catch((err) => {
      if (axios.isCancel(err)) {
        console.log('请求超时自动取消', err.message)
      }
    })

使用

bash 复制代码
const userLogin = async () => {
    const controller = new AbortController()
    let params = {
        signal: controller.signal,
    }
    const res = await postLogin(params)
    console.log(res)
}

将网络降一下速测试

打印

四、封装响应拦截response

javascript 复制代码
service.interceptors.response.use(
  (response: any) => { 
    // 2xx范围内的状态码触发 
    
    const res = response.data 
    // 自定义业务状态码处理
    if (res.code !== 200) {
      // 超出2xx范围的状态码 映射
      const ERROR_MAP: Record<number, string> = {
        400: '请求参数错误',
        401: '认证过期,请重新登录',
        403: '无权访问该资源',
        500: '服务器开小差了,请稍后再试',
        // 其他状态码
      } 
      const { errCode, errMsg } = res
      // HTTP状态码处理
      const message = ERROR_MAP[errCode] || errMsg || '请求处理失败'
      console.warn(message) // 错误信息提示
    } else {
      return res
    }
  },
  (error) => { 
    return Promise.reject(error)
  },
)

五、封装 http 请求

在http文件下创建axios实例

javascript 复制代码
import service from './request'
import axios from 'axios'

const http = {
  get(url: string, params: object) {
    return service({
      url,
      method: 'GET',
      params,
    }).catch((err) => {
      if (axios.isCancel(err)) {
        console.log('请求超时自动取消', err.message)
      }
    })
  },
  post(url: string, data: any) {
    return service({
      url,
      method: 'POST',
      data,
    }).catch((err) => {
      if (axios.isCancel(err)) {
        console.log('请求超时自动取消', err.message)
      }
    })
  },
}

export default http 

六、使用

在api文件夹下新建文件并引入

javascript 复制代码
import http from '../http'

export const getLogin = (params: object) => http.get('/login', params) // 登录

export const getUserLogin = (data = {}) => http.get('/user/login' , data) //获取当前登录人信息

注:如果后端接口前缀有很多一样的可以新建文件再统一 引入

javascript 复制代码
import { base1 , base2} from '../XXX'
export const getLogin = (params: object) => http.get(base + '/XXX', params) // 登录
export const getUserLogin = (params: object) => http.get(base2 + '/XXX', params) // 获取当前登录人信息

页面中引入接口并使用

javascript 复制代码
const handleLogin = async () => {
    const res = await getLogin ()
    console.log(res)
}

总结

完整的request代码 ,其中一些细节根据不同项目需要不同调整~

bash 复制代码
import axios from 'axios'

const base = import.meta.env.VITE_APP_API // 接口地址

const service = axios.create({
  baseURL: base,
  timeout: 60000, // 设置超时时间
  // headers: { 'X-Custom-Header': 'foobar' }, // 设置请求头
})

//超时辅助函数
function newAbortSignal(timeoutMs: number) {
  const abortController = new AbortController()
  setTimeout(() => abortController.abort(), timeoutMs || 0)

  return abortController.signal
}

const RETRY_COUNT = 3
let retry = 0 // 重试次数

service.interceptors.request.use(
  (config: any) => {
    // Do something before request is sent
    console.log(config)

    config.signal = newAbortSignal(config.timeout || 60000)

    const needToken = !(config.params?.noToken || config.data?.noToken)

    // 示例1:添加token
    const token = localStorage.getItem('access_token')
    if (needToken) {
      config.headers['X-Token'] = `Bearer ${token}` // 根据服务器设置请求头
    }

    //示例2:不验证token
    delete config.params.noToken
    delete config.params.signal

    // 示例3:Content-Type动态处理
    if (config.data instanceof FormData) {
      config.headers['Content-Type'] = 'multipart/form-data' // 文件上传
    }

    // 示例4:请求重试
    config.metaData = { startTime: Date.now() }

    return config
  },
  (error) => {
    // Do something with request error

    if (retry < RETRY_COUNT) {
      retry++
      console.warn(`请求超时,正在进行第 ${retry} 次重试...`)
      return service.request(error.config)
    }
    return Promise.reject(error)
  },
)

service.interceptors.response.use(
  (response: any) => {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    console.log(response)

    const endTime = Date.now()
    const duration = endTime - response.config.metaData.startTime
    console.log(`请求 ${response.config.url} 耗时 ${duration}ms`)

    // 2xx范围内的状态码

    // 统一处理数据结构
    const res = response.data

    // 自定义业务状态码处理
    if (res.code !== 200) {
      // 超出2xx范围的状态码 映射
      const ERROR_MAP: Record<number, string> = {
        400: '请求参数错误',
        401: '认证过期,请重新登录',
        403: '无权访问该资源',
        500: '服务器开小差了,请稍后再试',
        // 其他状态码
      }
      // 错误信息解析
      const { errCode, errMsg } = res
      // HTTP状态码处理
      const message = ERROR_MAP[errCode] || errMsg || '请求处理失败'
      console.warn(message) // 错误信息提示
    } else {
      return res
    }
  },
  (error) => {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    console.log(error)
    return Promise.reject(error)
  },
)

export default service

参考 :axios官网

相关推荐
Dontla8 分钟前
为什么React列表项需要key?(React key)(稳定的唯一标识key有助于React虚拟DOM优化重绘大型列表)
javascript·react.js·ecmascript
EndingCoder1 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客2 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
德育处主任Pro3 小时前
『React』Fragment的用法及简写形式
前端·javascript·react.js
CodeBlossom3 小时前
javaweb -html -CSS
前端·javascript·html
CodeCraft Studio3 小时前
【案例分享】如何借助JS UI组件库DHTMLX Suite构建高效物联网IIoT平台
javascript·物联网·ui
打小就很皮...4 小时前
HBuilder 发行Android(apk包)全流程指南
前端·javascript·微信小程序
集成显卡5 小时前
PlayWright | 初识微软出品的 WEB 应用自动化测试框架
前端·chrome·测试工具·microsoft·自动化·edge浏览器
前端小趴菜055 小时前
React - 组件通信
前端·react.js·前端框架
Amy_cx6 小时前
在表单输入框按回车页面刷新的问题
前端·elementui