文章目录
- [从接口文档到前端调用:Axios 封装与实战全流程详解](#从接口文档到前端调用:Axios 封装与实战全流程详解)
- 1.如何看接口文档?
-
- [1.1 GET](#1.1 GET)
- [1.2 POST](#1.2 POST)
- 2.为什么要封装请求拦截器和响应拦截器?如何封装?
-
- [2.1 封装axios实例](#2.1 封装axios实例)
- [2.2 封装拦截器](#2.2 封装拦截器)
- [2.3 拦截器实践](#2.3 拦截器实践)
- 3.如何在实际的项目中使用axios
-
- [3.1 GET](#3.1 GET)
- [3.2 POST](#3.2 POST)
- [3.3. DELETE](#3.3. DELETE)
- [3.4 PUT](#3.4 PUT)
- [3.5 PATCH](#3.5 PATCH)
从接口文档到前端调用:Axios 封装与实战全流程详解
1.如何看接口文档?
在一个接口文档中,有很多的请求类型(也叫 HTTP 方法 / 动作)
- GET
- POST
- PUT
- PATCH
- DELETE
这里仅以 GET 和 POST 做讲解,其他的请求类型,都类似
1.1 GET
注意:GET 跟 URL 息息相关
来看一个具体的例子:


首先,接口都会有一个 baseUrl,作为获取数据的地址,使用不同的接口时,又会有不同的路径,比如这个就是/my/cate/info
第一部分:请求参数(Request Parameters)
Query 参数和 Header 参数
Query 参数和 Header 参数
query 跟 url 息息相关
header 跟身份验证相关,就是说,想让这个请求发送给接口,必须满足一些条件,header 就像一把钥匙
文档中这两部分都必须传对,否则接口要么报错,要么不给你数据。
- Query 参数
-
出现在 URL 上。
-
在这个接口里:
GET /my/cate/info?id=1284这里的
id=1284就是 文章分类的 id,告诉后台我要取哪一个分类的详情。 -
所以:Query 参数就是用来指定查询条件的。
- Header 参数
- 放在 HTTP 请求的 请求头里。
- 这里要求的参数是:
Authorization: Bearer <token>
Authorization:英语中授权的意思
- 作用:用来验证用户身份(你是否已经登录)。
- 也就是说:
- 如果没有这个 token → 后台会返回 401 身份认证失败。
- 有正确 token → 才能拿到分类详情。
第二部分:响应(Response)
javascript
{
"code": 0,
"message": "获取文章分类成功!",
"data": {
"id": 1070,
"cate_name": "科技",
"cate_alias": "keji"
}
}
- code :业务状态码。
0表示成功,1表示异常。
- message:提示消息(给人看的,比如"成功/失败原因")。
- data :真正的业务数据,这里是文章分类的详情对象。
id:分类 ID。cate_name:分类名称(比如 "科技")。cate_alias:分类别名(比如 "keji")。
这部分就是告诉你:调用成功以后,后台会返回什么样的数据结构,你前端代码里就可以用这些字段来展示页面。
1.2 POST
看如下例子:返回响应部分不做介绍,POST 请求方法没有 Query 参数,而是 Body 参数


Body 参数(请求体)
这是 POST 接口的重点,和 GET 很不同:
- 位置 :请求报文的 body 部分,不在 URL 上。
- 格式 :这里文档写了
application/json,说明 body 要用 JSON 格式。 - 作用 :用来传递 新增数据的内容。
在文档里,它定义了两个字段:
- cate_name (string)
- 文章分类名字,比如"娱乐"、"科技"。
- 必填,长度限制:1--10 个非空字符。
- cate_alias (string)
- 文章分类别名,比如"yule"、"keji"。
- 必填,长度限制:1--15 个大小写字母和数字组合。
示例 JSON:
{
"cate_name": "娱乐",
"cate_alias": "yule"
}
为什么 GET 没有 Body,而 POST 要用 Body?
GET:只是获取数据,不修改,所以参数少,放 URL 上即可。
POST:要创建一条新数据,通常包含多个字段(标题、别名、内容......),如果写在 URL 会很长很乱,所以必须放到 Body 里,结构化成 JSON。
2.为什么要封装请求拦截器和响应拦截器?如何封装?
简单来说,实际开发过程中,不能每一次都手动的在请求头中加入授权的 token,而请求拦截器,会拦截请求将每个授权的 token 加入到本次的请求头当中.
统一封装 axios 请求模板:
官方文档:https://www.axios-http.cn/docs/interceptors
javascript
import axios from 'axios'
const baseURL = 'http://big-event-vue-api-t.itheima.net'
const instance = axios.create({
// 1. 基础地址,超时时间(配置项)
})
//请求拦截器
instance.interceptors.request.use(
(config) => {
// 2. 携带token,将 token 值赋给请求头
return config
},
(err) => Promise.reject(err)
)
//响应拦截器
instance.interceptors.response.use(
//http 返回 200 成功
(res) => {
// 3. 正确拿到了业务数据
// 4. 业务逻辑错误,例如限制密码字母大写
return res
},
(err) => {
// 5. 处理http 返回401错误
return Promise.reject(err)
}
)
export default instance
- 将封装写在
src/utils/request.js - 首先,创建一个 axios 实例
- 其次,写出请求拦截器和响应拦截器
2.1 封装axios实例
(1)统一配置
- 每个接口都要用到的公共参数,比如:
baseURL(基础路径)timeout(超时时间)headers(请求头,常常要放 token)
- 如果不封装,每次
axios.get()/axios.post()都要手动写,很麻烦。 - 封装后 → 写一次,所有请求自动带上。
timeout:请求超过 x 毫秒 还没响应,就自动报错,进入
.catch()请求中几乎所有接口都需要,而且不会频繁变化 的东西,适合直接写在
axios.create()的headers里,所以 token 不应该写在这里,token 应写在拦截器中
(2)更好的可维护性
- 以后如果
baseURL要改(比如从测试环境 → 正式环境),只需要改request.js这一处。 - 如果不封装,你得在项目里到处找 URL,一个个修改,容易遗漏。
(3)添加请求/响应拦截器
(4)支持多实例
有些项目里:
- 一部分接口走
https://api.example.com - 另一部分接口走
https://upload.example.com
就可以创建两个不同的 axios 实例,互不影响。
封装axios实例代码如下:
javascript
import axios from 'axios'
const baseURL = 'http://big-event-vue-api-t.itheima.net'
const instance = axios.create({
baseURL,
timeout: 100000
})
2.2 封装拦截器
官方文档中的拦截器
javascript
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
分析:
request 拦截器的代码是一样的,关键在于拿到的对象不一样,一个是 config,一个是 response
- config 对象
- axios 会先把你传入的参数转成一个"配置对象",这个配置对象就是 config 对象
- response 对象
- 浏览器原生的 XHR 或 fetch 会产生一个响应结果,axios 会把这个结果"包装"成一个对象
注意:
- 这里的 axios.替换成你对应的 axios 实例
- function(config) 也可以替换成对应的箭头函数()=>{}
2.3 拦截器实践
请求拦截器:使用 pinia 存储的 token,将 token 值赋给请求头
javascript
instance.interceptors.request.use(
(config) => {
const userStore = useUserStore()
if (userStore.token) {
config.headers.Authorization = userStore.token
}
return config
},
(err) => Promise.reject(err)
响应拦截器:
-
成功拿到响应,直接返回,没拿到服务异常
-
若错误,根据错误类型提示或跳转路由
javascript
instance.interceptors.response.use(
(res) => {
if (res.data.code === 0) {
return res
}
ElMessage({ message: res.data.message || '服务异常', type: 'error' })
return Promise.reject(res.data)
},
(err) => {
ElMessage({ message: err.response.data.message || '服务异常', type: 'error' })
console.log(err)
if (err.response?.status === 401) {
router.push('/login')
}
return Promise.reject(err)
}
)
导出
javascript
export default instance
export { baseURL }
3.如何在实际的项目中使用axios
3.1 GET
无需请求参数的 GET

在 src/api 下创建自定义的 js 文件,如 article.js.存放跟文章相关的 api
src/api/article.js
- 导入封装好的方法
javascript
import request from '@/utils/request'
- 实现 api
javascript
//获取文章分类
export const artGetChannelsService=()=>request.get('/my/cate/list')
-
在具体的.vue 文件中使用
-
导入该方法
javascriptimport { artGetChannelsService} from '@/api/article' -
使用该方法
javascriptconst res =await artGetChannelsService()
-
需要请求参数的 GET

API 封装:
javascript
// 获取文章分类详情 ?id=xxx
export const artGetChannelDetailService = (id) => {
return request.get('/my/cate/info', {
params: { id } // => /my/cate/info?id=1284
})
}
为什么写 params 呢?
因为能拼到 url 后面
在 .vue 里使用:
javascript
import { artGetChannelDetailService } from '@/api/article'
const id = route.query.id // 比如路由里带着 ?id=1284
await artGetChannelDetailService(id)
3.2 POST
以这个为例:

- 导入封装好的方法
javascript
import request from '@/utils/request'
- 实现 api
javascript
//添加文章分类
export const artAddChannelService=(data)=>request.post('/my/cate/add',data)
-
在具体的.vue 文件中使用
-
导入该方法
javascriptimport { artAddChannelService} from '@/api/article' -
使用该方法,此时注意了,POST 是需要我们传参的
javascript//定义表单数据 const formModel=ref({ cate_name:'', cate_alias:'' }) await artAddChannelService(formModel.value)
-
3.3. DELETE
Delete 也是需要一个请求参数,写法跟带参数的 GET 一样
API 封装:
javascript
// 删除文章分类
export const artDelChannelService = (id) =>
request.delete('/my/cate/del', {
params: { id }
})
3.4 PUT
put 跟 post 写法一样,除了 request 方法是 put
API 封装:
javascript
export const artEditChannelService =(data)=> request.put('/my/cate/info',data)
在实际写法中,也可以不用形参 data,直接传对象,比如
javascript
//更新个人信息
export const userUpdateInfoService = ({ id, nickname, email }) =>
request.put('/my/userinfo', { id, nickname, email })
3.5 PATCH

API 封装:
跟 post 一样
javascript
//上传头像
export const userUploadAvatarService = (avatar) => request.patch('/my/update/avatar', { avatar })