【Axios接口封装+前端规范】中后台项目实战:从请求参数到异常兜底,一站式搞定接口请求规范,避开团队协作混乱与维护噩梦!

📑 文章目录
- 一、为什么要做「接口请求规范」?
- 二、请求参数规范
- [2.1 参数怎么传?GET / POST 怎么选?](#2.1 参数怎么传?GET / POST 怎么选?)
- [2.2 统一封装请求参数](#2.2 统一封装请求参数)
- [2.3 参数命名和格式约定](#2.3 参数命名和格式约定)
- 三、响应处理规范
- [3.1 响应格式要统一](#3.1 响应格式要统一)
- [3.2 响应拦截器:统一剥一层](#3.2 响应拦截器:统一剥一层)
- [3.3 不同后端约定的兼容写法](#3.3 不同后端约定的兼容写法)
- 四、异常兜底规范
- [4.1 常见异常来源](#4.1 常见异常来源)
- [4.2 异常兜底要做什么?](#4.2 异常兜底要做什么?)
- [4.3 完整异常处理示例](#4.3 完整异常处理示例)
- [4.4 业务层:按需捕获](#4.4 业务层:按需捕获)
- 五、完整实战示例
- [5.1 完整的 request 封装](#5.1 完整的 request 封装)
- [5.2 业务调用示例(Vue 组件)](#5.2 业务调用示例(Vue 组件))
- 六、常见坑与最佳实践
- 七、小结
- [🔍 系列模块导航](#🔍 系列模块导航)
- [📝 API 与异步请求规范](#📝 API 与异步请求规范)
- [📚 系列总览](#📚 系列总览)
同学们好,我是 Eugene(尤金),一名多年中后台前端开发工程师。
(Eugene 发音 /juːˈdʒiːn/,大家怎么顺口怎么叫就好)
很多前端开发者都会遇到一个瓶颈:
代码能跑,但不够规范;功能能实现,但维护起来特别痛苦;一个人写没问题,一到团队协作就各种混乱、踩坑、返工。
想写出干净、优雅、可维护 的专业代码,靠的不是天赋,而是体系化的规范 + 真实实战经验。
这一系列《前端规范实战》,我会用大白话 + 真实业务场景,不讲玄学、不堆理论,只分享能直接落地的规范、标准与避坑指南。
帮你从「会写代码」真正升级为「会写优质、可维护、团队级别的代码」。
一、为什么要做「接口请求规范」?
前端工程里,接口调用通常占了很大比重。如果没有统一规范,很容易出现:
- 参数是
params还是query、用GET还是POST乱用; - 有的接口用
data.code === 0,有的用data.success,判断逻辑分散; - 错误只
console.log不处理,页面没有任何提示; - 重复逻辑散落各处,改一处要改很多地方。
做好「请求参数 + 响应处理 + 异常兜底」这三块,能让代码更清晰、更好维护。下面按这三块来拆解。
二、请求参数规范
2.1 参数怎么传?GET / POST 怎么选?
简单记法:
- GET:查数据,参数放在 URL 上(query),无请求体;
- POST:增、改、删,或参数多、敏感时,参数放在请求体(body)。
常见错误:用 GET 传大量或敏感参数。GET 会出现在地址栏和日志里,不安全。
js
// ❌ 不推荐:GET 传复杂或敏感数据
axios.get('/api/user/login', {
params: {
username: 'admin',
password: '123456', // 明文出现在 URL 里
}
})
// ✅ 推荐:登录用 POST,密码放 body
axios.post('/api/user/login', {
username: 'admin',
password: '123456',
})
[⬆ 返回目录](#⬆ 返回目录)
2.2 统一封装请求参数
把「参数处理」集中在一个地方,后续改参数格式会轻松很多。
js
// utils/request.js
import axios from 'axios'
// 创建实例
const instance = axios.create({
baseURL: '/api',
timeout: 10000,
})
// 请求拦截器:统一处理参数
instance.interceptors.request.use(
(config) => {
// 1. 统一加 token
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
// 2. GET 请求:params 保持原样,Axios 会自动拼到 URL
// 3. POST 请求:data 保持原样,Axios 会序列化到 body
return config
},
(error) => Promise.reject(error)
)
export default instance
[⬆ 返回目录](#⬆ 返回目录)
2.3 参数命名和格式约定
建议和接口文档保持一致,例如:
- 分页:
pageNum、pageSize; - 时间:
startTime、endTime(ISO 字符串或时间戳); - 布尔:
isActive、enabled等,统一用true/false。
js
// ✅ 分页参数示例
const fetchUserList = (pageNum = 1, pageSize = 10) => {
return request.get('/user/list', {
params: {
pageNum,
pageSize,
// 后端约定:0-全部 1-启用 2-禁用
status: 1,
}
})
}
[⬆ 返回目录](#⬆ 返回目录)
三、响应处理规范
3.1 响应格式要统一
后端一般会约定类似结构:
json
{
"code": 0,
"message": "success",
"data": { ... }
}
前端用统一的判断逻辑,不要有的地方看 code,有的地方看 success。
[⬆ 返回目录](#⬆ 返回目录)
3.2 响应拦截器:统一剥一层
在响应拦截器里统一处理 code,把业务数据直接返回给调用方,调用处只关心业务数据。
js
// utils/request.js 响应拦截器
instance.interceptors.response.use(
(response) => {
const { code, message, data } = response.data
// 业务成功
if (code === 0 || code === 200) {
return data
}
// 业务失败:如 401 未登录、403 无权限
if (code === 401) {
// 清 token、跳登录等
localStorage.removeItem('token')
window.location.href = '/login'
return Promise.reject(new Error('未登录'))
}
if (code === 403) {
return Promise.reject(new Error('无权限'))
}
// 其他业务错误
return Promise.reject(new Error(message || '请求失败'))
},
(error) => {
// 网络错误、超时等,交给后面的异常兜底
return Promise.reject(error)
}
)
这样在业务代码里,直接用 data:
js
// 业务代码中
const list = await request.get('/user/list')
// list 已经是 data 部分,不再需要 response.data.data
console.log(list)
[⬆ 返回目录](#⬆ 返回目录)
3.3 不同后端约定的兼容写法
有的后端用 code === 0 表示成功,有的用 code === 200 或 success === true,可以集中配置:
js
// config/api.js
export const SUCCESS_CODES = [0, 200]
// utils/request.js
if (SUCCESS_CODES.includes(code)) {
return data
}
[⬆ 返回目录](#⬆ 返回目录)
四、异常兜底规范
4.1 常见异常来源
- 网络错误:断网、超时;
- HTTP 状态码:404、500;
- 业务错误:
code !== 0,如参数错误、余额不足; - 前端逻辑错误:如解析 JSON 失败。
[⬆ 返回目录](#⬆ 返回目录)
4.2 异常兜底要做什么?
- 统一提示用户(如 Toast、Message);
- 区分可重试 / 不可重试;
- 可选:上报错误,方便排查。
[⬆ 返回目录](#⬆ 返回目录)
4.3 完整异常处理示例
js
// utils/request.js
import { Message } from 'element-ui' // 或你的 UI 库
instance.interceptors.response.use(
(response) => { /* 上面已有,省略 */ },
(error) => {
let message = '网络异常,请稍后重试'
if (error.response) {
// 有 response:服务器返回了错误
const { status, data } = error.response
switch (status) {
case 400:
message = data?.message || '请求参数错误'
break
case 401:
message = '未登录或登录已过期'
localStorage.removeItem('token')
window.location.href = '/login'
break
case 403:
message = '没有权限'
break
case 404:
message = '请求的资源不存在'
break
case 500:
message = '服务器错误,请稍后重试'
break
default:
message = data?.message || `请求失败(${status})`
}
} else if (error.request) {
// 有 request 但无 response:网络异常
if (error.code === 'ECONNABORTED') {
message = '请求超时,请检查网络'
} else {
message = '网络连接失败,请检查网络'
}
} else {
message = error.message || '未知错误'
}
Message.error(message)
return Promise.reject(error)
}
)
[⬆ 返回目录](#⬆ 返回目录)
4.4 业务层:按需捕获
有时某个接口希望自己处理错误,不弹出全局提示,可以:
js
// 1. 在接口配置里标记「静默」
// 2. 或在业务里用 try-catch 包一层
try {
const res = await request.post('/user/delete', { id: 1 })
Message.success('删除成功')
// 刷新列表等
} catch (e) {
// 这里已经不会弹全局提示,因为上面拦截器 reject 后,这里会 catch
// 但拦截器里已经 Message.error 了,如果不想重复弹,可以:
// 方案 A:在 error 上挂一个标记 skipGlobalError
// 方案 B:这个接口单独用原始 axios,不走拦截器
}
更推荐做法:在请求配置中加 skipGlobalError,拦截器里判断:
js
// 发起请求时
request.post('/user/delete', { id: 1 }, { skipGlobalError: true })
// 响应拦截器 error 中
if (!error.config?.skipGlobalError) {
Message.error(message)
}
[⬆ 返回目录](#⬆ 返回目录)
五、完整实战示例
5.1 完整的 request 封装
js
// utils/request.js
import axios from 'axios'
import { Message } from 'element-ui'
const instance = axios.create({
baseURL: process.env.VUE_APP_BASE_API || '/api',
timeout: 10000,
})
// 请求拦截
instance.interceptors.request.use(
(config) => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
// 响应拦截
instance.interceptors.response.use(
(response) => {
const { code, message, data } = response.data
if (code === 0 || code === 200) {
return data
}
if (code === 401) {
localStorage.removeItem('token')
window.location.href = '/login'
return Promise.reject(new Error('未登录'))
}
const err = new Error(message || '请求失败')
err.code = code
return Promise.reject(err)
},
(error) => {
const skipGlobalError = error.config?.skipGlobalError
let msg = '网络异常,请稍后重试'
if (error.response) {
const { status, data } = error.response
msg = data?.message || ({
400: '请求参数错误',
401: '未登录或登录已过期',
403: '没有权限',
404: '资源不存在',
500: '服务器错误',
})[status] || `请求失败(${status})`
if (status === 401) {
localStorage.removeItem('token')
window.location.href = '/login'
}
} else if (error.request) {
msg = error.code === 'ECONNABORTED' ? '请求超时' : '网络连接失败'
} else {
msg = error.message || '未知错误'
}
if (!skipGlobalError) {
Message.error(msg)
}
return Promise.reject(error)
}
)
export default instance
[⬆ 返回目录](#⬆ 返回目录)
5.2 业务调用示例(Vue 组件)
html
<template>
<div>
<el-button @click="loadList" :loading="loading">加载列表</el-button>
<el-table :data="list">
<el-table-column prop="name" label="姓名" />
<el-table-column prop="phone" label="手机" />
</el-table>
</div>
</template>
<script>
import request from '@/utils/request'
export default {
data() {
return {
list: [],
loading: false,
pageNum: 1,
pageSize: 10,
}
},
created() {
this.loadList()
},
methods: {
async loadList() {
this.loading = true
try {
// 直接拿到 data,结构清晰
const res = await request.get('/user/list', {
params: {
pageNum: this.pageNum,
pageSize: this.pageSize,
}
})
this.list = res.list || res
} catch (e) {
// 拦截器已弹错,这里可做额外逻辑(如重试、记录)
console.error('加载列表失败', e)
} finally {
this.loading = false
}
},
},
}
</script>
[⬆ 返回目录](#⬆ 返回目录)
六、常见坑与最佳实践
| 场景 | 坑 | 建议 |
|---|---|---|
| 重复请求 | 快速连点造成重复提交 | 按钮加 loading,或防抖/节流 |
| Token 过期 | 多个请求同时 401,多次跳登录 | 加请求队列,收到 401 后统一处理 |
| 取消请求 | 切换页面前请求未结束,数据被旧请求覆盖 | 用 AbortController 或 axios 的 cancelToken 取消 |
| 文件上传 | 用 JSON,大文件慢或失败 | 用 FormData,Content-Type 交给浏览器 |
| 超时 | 默认超时过长 | 按接口类型设 timeout(列表 10s,上传 60s 等) |
[⬆ 返回目录](#⬆ 返回目录)
七、小结
- 请求参数:GET 查、POST 改/增/删;参数统一在拦截器处理;命名和格式与后端约定一致。
- 响应处理 :在响应拦截器统一解析
code,成功时直接返回data,失败统一reject。 - 异常兜底 :区分网络错误、HTTP 错误、业务错误;统一提示;支持
skipGlobalError做静默处理。
按这三块把接口层规范好,业务代码会清爽很多,后续维护和排查问题都会更轻松。
[⬆ 返回目录](#⬆ 返回目录)
🔍 系列模块导航
📝 API 与异步请求规范
一、《Axios 统一封装实战:拦截器配置 + baseURL 优化 + 接口规范,避坑重复代码|API 与异步请求规范篇》
二、《Axios 接口请求规范实战:请求参数 / 响应处理 / 异常兜底,避坑中后台 API 调用混乱|API 与异步请求规范篇》
三、《Axios + Vue 错误处理规范:中后台项目实战,统一捕获系统 / 业务 / 接口异常|API 与异步请求规范篇》
四、《前端实战:Excel 导入导出规范(命名 + 校验 + 错误处理 + 统一交互)|API 与异步请求规范篇》
👉 跟着系列慢慢学,把技术功底扎扎实实地打牢~
📚 系列总览
📚 系列总览
前端体系化学习完全体:基础 → 规范 → 架构 → 大厂面试
四套系列、百余篇高质量实战文,从入门到进阶,一站式补齐前端核心能力
- 前端基础实战系列 : 《前端基础实战:JS/TS与Vue体系化扫盲(47 篇完整目录 + 避坑)》
- 前端规范实战系列 : 《JS/TS/Vue 前端规范实战:从写对到写优,搞定中后台规范落地,打造可维护代码(40 篇全目录)》
- 前端架构实战系列:聚焦工程化、性能优化、可维护架构、中后台体系设计(持续更新中)
- 前端大厂面试系列:覆盖高频考点、手写题、项目深挖、简历与面试技巧(规划中)
每个系列完结后,都会整理成一篇完整导航文并附上直达链接,方便大家按顺序、体系化学习。
全套内容持续更新中,敬请期待~
[⬆ 返回目录](#⬆ 返回目录)
技术成长,从来不是比谁写得快,而是比谁写得稳、规范、可维护。
哪怕每次只吃透一条规范,长期下来,差距会非常明显。
后续我会持续更新前端规范、工程化、可维护代码相关实战干货,帮你告别面条代码、维护噩梦,在开发与面试中更有底气。
觉得有用欢迎 点赞 + 收藏 + 关注,不错过每一篇实战内容。
我是 Eugene,与你一起写规范、写优质代码,我们下篇干货见~