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官网

相关推荐
장숙혜3 分钟前
ElementUi的Dropdown下拉菜单的详细介绍及使用
前端·javascript·vue.js
火柴盒zhang6 分钟前
websheet之 编辑器
开发语言·前端·javascript·编辑器·spreadsheet·websheet
某公司摸鱼前端8 分钟前
uniapp 仿企微左边公司切换页
前端·uni-app·企业微信
WKK_11 分钟前
uniapp自定义封装tabbar
前端·javascript·小程序·uni-app
莫问alicia12 分钟前
react 常用钩子 hooks 总结
前端·javascript·react.js
Mintopia21 分钟前
图形学中的数学基础与 JavaScript 实践
前端·javascript·计算机图形学
Mintopia28 分钟前
Three.js 制作飘摇的草:从基础到进阶的全流程教学
前端·javascript·three.js
BillKu28 分钟前
Vue3父子组件数据双向同步实现方法
前端·javascript·vue.js
红尘散仙1 小时前
七、WebGPU 基础入门——Texture 纹理
前端·rust·gpu
jaywongX1 小时前
Base64编码原理:二进制数据与文本的转换技术
前端·javascript·vue