vue3+axios挑战最简洁实用的配置封装+接口调用:请求拦截器、响应拦截器、通用请求方法(单个请求/并发请求/下载文件)、统一接口管理

axios 官方文档:入门指南 | axios | Promise based HTTP client

axios GitHub 主页:GitHub - axios/axios: Promise based HTTP client for the browser and node.js · GitHub

  1. 安装 axios
bash 复制代码
# 使用 npm 安装:
npm install axios
# 或者 yarn 安装:
yarn add axios
  1. src下新建文件夹apiapi下新建文件index.js用于配置请求逻辑
js 复制代码
/* src/api/index.js */

// 1、引入 axios
const axios = require("axios").default  // axios.<method> 能够提供自动完成和参数类型推断功能

// 2、创建请求实例
const instance = axios.create({
  baseURL: "https://your-base-api.com/endpoint",  // 拼接在 url 前面的基础 URL
  timeout: 10000,  // 请求超时前等待的毫秒数
})

// 3、添加请求拦截器
instance.interceptors.request.use(
  function (config) {
    // 在请求发送之前执行以下操作
    const token = localStorage.getItem("token")  // 获取存储的 token
    if (token) {
      config.headers["authorization"] = token  // 请求头添加 token 认证
    }
    // 针对 get 请求避免使用旧缓存
    if (config.method === "get") {
      config.headers["cache-control"] = "no-cache"
    }

    return config
  },
  function (error) {
    // 处理请求错误
    console.log("请求错误", error)

    return Promise.reject(error)
  },
)

// 4、添加响应拦截器
instance.interceptors.response.use(
  function (response) {
    // 状态码在 2xx 范围内的响应会触发此函数
    // 处理响应数据
    console.log("响应数据", response)

    return response
  },
  function (error) {
    // 状态码不在 2xx 范围内的响应会触发此函数
    // 处理响应错误
    if (error.response) {
      console.log(error.response)  // 请求已发出,服务器返回了不在 2xx 范围内的状态码
    } else if (error.request) {
      console.log(error.request)  // 请求已发出,但未收到响应
    } else {
      console.log(error.config)  // 在设置请求时触发了错误
    }

    return Promise.reject(error)
  },
)

// 5、封装通用请求函数
// 见下文

export default instance
js 复制代码
/* src/api/index.js */

// 单个请求(*method-请求方法,*url-请求地址,custom-自定义操作,data-请求参数,config-其他配置)
export function request(method, url, custom = {}, data, config = {}) {
  // 请求配置
  const options = {
    url,  // 请求的目标 URL
    method,  // 请求使用的 HTTP 方法
    ...config,  // 添加其他配置项
  }
  // 根据请求方法处理参数(若需跳过 data 请在传参时赋值 null)
  if (data && data !== null) {
    if (method === "put" || method === "post" || method === "delete" || method === "patch") {
      options["data"] = data  // 作为请求体发送的数据,仅适用于 PUT、POST、DELETE、PATCH 请求方法
    } else {
      options["params"] = data  // 随请求发送的 URL 查询参数
    }
  }
  const { onSuccess, onFinally } = custom  // 从自定义操作中提取回调函数
  let errInfo = null  // 用于收集错误信息

  // axios 请求回调
  return instance(options)
    .then(function (response) {
      // 处理响应数据
      const resData = response.data
      if (onSuccess && typeof onSuccess === "function") {
        return onSuccess(resData)  // 执行成功回调函数(传递处理后的响应数据)
      }

      return response
    })
    .catch(function (error) {
      // 处理响应错误
      errInfo = error.response  // 收集错误信息传递给最终操作

      throw error
    })
    .finally(function () {
      // 请求完成最终操作
      if (onFinally && typeof onFinally === "function") {
        return onFinally(errInfo)  // 执行最终回调函数(传递处理后的响应错误)
      }
    })
}
js 复制代码
/* src/api/index.js */

// 并发请求(*requests-请求列表,custom-自定义操作)
export function requestAll(requests, custom = {}) {
  const { onSuccess, onFinally } = custom  // 从自定义操作中提取回调函数
  let errInfo = null  // 用于收集错误信息

  // axios 并发请求回调
  return Promise.all(requests)
    .then(function (responses) {
      // 处理响应数据列表
      const resDatas = []
      if (responses?.length) {
        for (let i = 0; i < responses.length; i++) {
          resDatas.push(responses[i].data)
        }
      }
      if (onSuccess && typeof onSuccess === "function") {
        return onSuccess(resDatas)  // 执行成功回调函数(传递处理后的响应数据列表)
      }

      return responses
    })
    .catch(function (error) {
      // 处理响应错误(error 只捕获第一个发生错误的请求所抛出的 AxiosError 对象)
      errInfo = error.response  // 收集错误信息传递给最终操作

      throw error
    })
    .finally(function () {
      // 请求完成最终操作
      if (onFinally && typeof onFinally === "function") {
        return onFinally(errInfo)  // 执行最终回调函数(传递处理后的响应错误)
      }
    })
}
js 复制代码
/* src/api/index.js */

// 下载请求(*method-请求方法,*url-请求地址,custom-自定义操作,data-请求参数,info-文件信息)
export function download(method, url, custom = {}, data, info = {}) {
  // 请求配置
  const options = {
    url,  // 请求的目标 URL
    method,  // 请求使用的 HTTP 方法
    responseType: "blob",  // 服务器响应的数据类型
  }
  // 根据请求方法处理参数(若需跳过 data 请在传参时赋值 null)
  if (data && data !== null) {
    if (method === "put" || method === "post" || method === "delete" || method === "patch") {
      options["data"] = data  // 作为请求体发送的数据,仅适用于 PUT、POST、DELETE、PATCH 请求方法
    } else {
      options["params"] = data  // 随请求发送的 URL 查询参数
    }
  }
  const { onSuccess, onFinally } = custom  // 从自定义操作中提取回调函数
  let errInfo = null  // 用于收集错误信息

  // axios 请求回调
  return instance(options)
    .then(function (response) {
      // 处理响应数据
      let resData = null
      if (response?.data) {
        resData = response.data
        const { filename } = info  // 从文件信息中提取文件名
        // 获取到文件流时执行下载操作(可封装为函数使用)
        let blob = null
        if (resData instanceof Blob) {
          blob = new Blob([resData]) // 确保文件流为 Blob 或 ArrayBuffer 类型
        } else {
          blob = new Blob([resData], { type: "application/octet-stream" })  // 否则尝试强制转换
        }
        const downloadUrl = window.URL.createObjectURL(blob)  // 使用 Blob 创建临时 URL
        // 创建 <a> 元素并触发下载
        const link = document.createElement("a")
        link.href = downloadUrl
        link.download = filename
        document.body.appendChild(link)  // 必须将其添加到 DOM 中
        link.click()
        document.body.removeChild(link)
        window.URL.revokeObjectURL(downloadUrl)  // 下载完成后释放内存
      }
      if (onSuccess && typeof onSuccess === "function") {
        return onSuccess(resData)  // 执行成功回调函数(传递处理后的响应数据)
      }

      return response
    })
    .catch(function (error) {
      // 处理响应错误
      errInfo = error.response  // 收集错误信息传递给最终操作

      throw error
    })
    .finally(function () {
      // 请求完成最终操作
      if (onFinally && typeof onFinally === "function") {
        return onFinally(errInfo)  // 执行最终回调函数(传递处理后的响应错误)
      }
    })
}
  1. api下新建文件modules.js用于统一管理接口(查看接口调用示例
js 复制代码
/* src/api/modules.js */

// 导入配置好的 axios 实例及请求函数
import instance, { request, requestAll, download } from "@/api"
// 封装接口函数便于组件中调用
export default {
	// 【模块 1】=========================
	// 单个请求示例:接口 A(调用接口时按需传参)
	example_url_a: (custom = {}, params, config = {}) => {
		return request("get", "/example/url/a", custom, params, config)  // 调用封装好的 request 函数
	},
	// 并发请求示例:接口 B+C+D(调用接口时若传参 params 请严格按照请求顺序)
	all_eub_euc_eud: (custom = {}, params = []) => {
	  // 使用 axios 默认方法处理每个接口
	  function exampleUrlB() {
	    return instance.post("/example/url/b", params[0])
	  }
	  function exampleUrlC() {
	    return instance.post("/example/url/c", params[1])
	  }
	  function exampleUrlD() {
	    return instance.post("/example/url/d")
	  }
	  // 调用封装好的 requestAll 函数
	  return requestAll([exampleUrlB(), exampleUrlC(), exampleUrlD()], custom)
	},
	// 【模块 2】=========================
	// 下载请求示例:接口 E(调用接口时按需传参)
	example_url_e: (custom = {}, data, info = {}) => {
	  return download("post", "/example/url/e", custom, data, info)  // 调用封装好的 download 函数
	},
}
  1. main.js中将接口模块文件modules.js挂载到全局
js 复制代码
/* src/main.js */
import { createApp } from "vue"
import App from "./App.vue"
import api from "./api/modules"  // 导入 modules.js

const app = createApp(App)
app.config.globalProperties.$api = api  // 挂载为全局属性(组件中使用 this.$api 获取)
  1. 在组件中调用接口
js 复制代码
/* example.vue */

// 单个请求接口函数调用示例
const params = {
  page: 1,
}
this.$api.example_url_a({
  onSuccess: (data) => {
    if (data) {
      // 处理响应数据
      console.log(data)
    },
  },
  onFinally: (error) => {
    // 执行最终操作以及处理响应错误
    console.warn(error)
  },
}, params)

// 并发请求接口函数调用示例
const params1 = {
  search: "搜索词",
}
const params2 = {
  filter: "过滤条件",
}
this.$api.all_eub_euc_eud({
  onSuccess: (datas) => {
    if (datas?.length) {
      // 处理响应数据列表
      console.log(datas[0], datas[1], datas[2])
    },
  },
  onFinally: (error) => {
    // 执行最终操作以及处理响应错误
    console.warn(error)
  },
}, [params1, params2])

// 下载请求接口函数调用示例
const params = {
  id: 123,
}
const info = {
  filename: "自定义文件名",
}
this.$api.example_url_e({
  onSuccess: (data) => {
    if (data) {
      // 处理响应数据
      console.log(data)
    },
  },
  onFinally: (error) => {
    // 执行最终操作以及处理响应错误
    console.warn(error)
  },
}, params, info)
相关推荐
yuhaiqiang1 小时前
上线一个人静态网站需要多少钱,难不难?
前端·后端·程序员
宸津-代码粉碎机1 小时前
Jar热部署进阶实战|修复原生方案OOM与类冲突问题,生产级无BUG优化方案
java·大数据·服务器·开发语言·前端·人工智能·python
To_OC9 小时前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
勇往直前plus10 小时前
Vue3(篇一) 核心概念——响应式模板语法与组件基础
前端·javascript·vue.js
咩咩啃树皮10 小时前
第43篇:Vue3计算属性(computed)完全精讲——缓存机制、依赖计算、业务最优解
前端·vue.js·缓存
徐小夕12 小时前
花了一周,3亿tokens,我开源了一款 Word 文档智能审查平台,文稿自动质检+可视化分析,告别低效人工审核
前端·算法·github
kyriewen14 小时前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js
Ivanqhz14 小时前
Rust &‘static str浅析
java·前端·javascript·rust
IT_陈寒14 小时前
SpringBoot这个分页坑,我踩了三天才爬出来
前端·人工智能·后端