axios 官方文档:入门指南 | axios | Promise based HTTP client
axios GitHub 主页:GitHub - axios/axios: Promise based HTTP client for the browser and node.js · GitHub
- 安装 axios
bash
# 使用 npm 安装:
npm install axios
# 或者 yarn 安装:
yarn add axios
- 在
src下新建文件夹api,api下新建文件index.js用于配置请求逻辑
- axios 基础配置(如需动态修改配置参数,请参考我之前的文章:vue3在public下封装config.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
- 封装单个请求函数
request(合并get/post等常用方法,查看函数使用示例)\*为必填参数
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) // 执行最终回调函数(传递处理后的响应错误)
}
})
}
- 封装并发请求函数
requestAll(合并get/post等常用方法,查看函数使用示例)\*为必填参数
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) // 执行最终回调函数(传递处理后的响应错误)
}
})
}
- 封装下载请求函数
download(合并get/post等常用方法,查看函数使用示例)\*为必填参数
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) // 执行最终回调函数(传递处理后的响应错误)
}
})
}
- 在
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 函数
},
}
- 在
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 获取)
- 在组件中调用接口
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)