从一个Bug谈前端响应拦截器的应用
一、问题场景
今天在开发商品管理系统时,遇到了一个有趣的问题:当添加重复的商品编号时,页面同时弹出了两条 "商品编号已存在"
错误提示:
这个问题暴露了前端错误处理机制的混乱,让我们从这个问题出发,深入了解响应拦截器
的应用。
二、问题分析
原始代码
// 响应拦截器
instance.interceptors.response.use(result => {if (result.data.code === 1) {return result.data;}ElMessage.error(result.data.msg || '服务异常');return Promise.reject(result.data);},err => {if(err.response.status === 401){ElMessage.error('请先登录!')router.push('/login')}else{ElMessage.error('服务异常');}return Promise.reject(err);}
)// 业务代码
const saveProduct = async () => {try {// ... 表单验证等代码 ...const res = await productAddService(submitData)if (res.code === 1) {ElMessage.success('添加成功')// ... 其他成功处理 ...} else {ElMessage.error(res.msg || '添加失败')}} catch (error) {ElMessage.error(error.msg || '商品编号已存在')}
}
错误提示重复的原因
- 后端返回数据:{code: 0, msg: “商品编号已存在”, data: null}
- 响应拦截器发现 code !== 1,显示错误消息并 reject
- 业务代码的 catch 块又显示了一次错误消息
三、解决方案
统一的响应拦截器处理
// src/utils/request.js
instance.interceptors.response.use(result => {// 业务成功if (result.data.code === 1) {return result.data;}// 业务失败,统一处理错误提示ElMessage.error(result.data.msg || '操作失败');return Promise.reject(result.data);},err => {// 处理HTTP错误if(err.response.status === 401){ElMessage.error('请先登录!')router.push('/login')}else{ElMessage.error('服务异常');}return Promise.reject(err);}
)
简化业务代码
const saveProduct = async () => {try {await productForm.value.validate()const submitData = {...productModel.value,price: Number(productModel.value.price)}const service = isEditMode.value ? productEditService : productAddServiceconst res = await service(submitData)// 只处理成功情况ElMessage.success(`${isEditMode.value ? '编辑' : '添加'}成功`)dialogVisible.value = falseproductList()resetProductModel()} catch (error) {// 错误已在拦截器中处理,这里不需要重复处理return}
}
四、响应拦截器
什么是响应拦截器
这里我进行一个类比,想象你在一个公司工作:
- 你就是业务部门(前端业务代码)
- 前台小姐姐就是响应拦截器
- 各种快递就是服务器返回的数据
场景一:正常快递
快递 → 前台验收 → 签字 → 转交给你
对应代码:
// 响应拦截器(前台小姐姐)
axios.interceptors.response.use(response => {if (response.data.code === 1) { // 检查快递是否完好return response.data // 转交给业务部门}}
)// 业务代码(你)
const res = await getProductList() // 直接收到处理好的快递
console.log(res.data) // 使用快递内容
场景二:问题快递
坏快递 → 前台拒收 → 你完全不用处理
对应代码:
// 响应拦截器(前台小姐姐)
axios.interceptors.response.use(response => {if (response.data.code !== 1) { // 发现快递有问题ElMessage.error('快递有问题') // 通知你快递有问题return Promise.reject() // 直接拒收,不给你添麻烦}}
)// 业务代码(你)
try {const res = await getProductList()// 只需要处理正常情况
} catch {// 问题已经被前台处理了,你不用管
}
响应拦截器就像这个"前台接待",它在服务器响应返回到我们的业务代码之前,对所有响应进行统一的处理
。
为什么需要响应拦截器?
- 没有响应拦截器时:
// 每个业务请求都需要重复处理这些情况
const getProductList = async () => {try {const res = await axios.get('/api/products')if (res.data.code === 1) { // 成功return res.data.data} else if (res.data.code === 401) { // 未登录ElMessage.error('请先登录')router.push('/login')} else { // 其他错误ElMessage.error(res.data.msg)}} catch (error) {ElMessage.error('网络错误')}
}const addProduct = async () => {try {const res = await axios.post('/api/product/add')// 又要重复上面的代码...} catch (error) {// 又要重复上面的代码...}
}
- 使用响应拦截器后:
// 统一的响应处理
axios.interceptors.response.use(response => {// 统一处理成功和失败if (response.data.code === 1) {return response.data}// 统一处理未登录if (response.data.code === 401) {ElMessage.error('请先登录')router.push('/login')return Promise.reject(response.data)}// 统一处理错误提示ElMessage.error(response.data.msg)return Promise.reject(response.data)},error => {// 统一处理网络错误ElMessage.error('网络错误')return Promise.reject(error)}
)// 业务代码变得简洁
const getProductList = async () => {try {const res = await axios.get('/api/products')return res.data // 只需处理成功的情况} catch (error) {// 错误已经在拦截器中处理过了}
}
四、请求流程图
请求发起 → 请求拦截器 → 服务器 → 响应拦截器
→ 业务代码
五、最佳实践总结
- 响应拦截器职责
- 统一处理响应数据格式
- 统一处理错误提示
- 处理特殊状态码(如401未登录)
- 转换服务端数据结构(如果需要)
- 业务代码职责
- 关注业务逻辑
- 处理成功场景
- 可以选择性地处理特定错误
- 不重复错误提示
- 错误处理原则
- 统一入口处理错误
- 避免重复提示
- 提供清晰的错误信息
- 合理使用 Promise.reject()
六、扩展应用
处理登录失效
if (err.response.status === 401) {ElMessage.error('登录已过期,请重新登录')router.push('/login')
}
处理网络错误
if (!error.response) {ElMessage.error('网络连接失败,请检查网络设置')
}
处理特定业务错误
if (result.data.code === 100001) {// 处理特定业务错误码handleSpecialError(result.data)return Promise.reject(result.data)
}
七、总结
响应拦截器就像一个尽职尽责的前台,帮你处理了所有烦琐的检查工作,让我们可以专注于核心业务。
相关文章:

从一个Bug谈前端响应拦截器的应用
一、问题场景 今天在开发商品管理系统时,遇到了一个有趣的问题:当添加重复的商品编号时,页面同时弹出了两条 "商品编号已存在" 错误提示: 这个问题暴露了前端错误处理机制的混乱,让我们从这个问题出发&…...

JS进阶DAY4|节点操作
嘿👋 今天我们要一起深入探索JavaScript中的DOM操作,这是前端开发中不可或缺的技能。🌟 准备好了吗?让我们一起跳进DOM的海洋,看看怎么用代码操控网页的结构吧! 目录 1. 增加节点 1.1 使用 appendChild 方…...

【Web】2023安洵杯第六届网络安全挑战赛 WP
目录 Whats my name easy_unserialize signal Swagger docs 赛题链接:GitHub - D0g3-Lab/i-SOON_CTF_2023: 2023 第六届安洵杯 题目环境/源码 Whats my name 第一段正则用于匹配以 include 结尾的字符串,并且在 include 之前,可以有任…...
go 语言中协程和GMP模型
为什么需要协程? 协程用来更加精细地利用线程,支撑超高的并发的。协程,从 runtime 的角度看,协程就是一个被调度的 g 结构体。 G 就是协程,M 是线程,P 是为了优化多线程并发时,会抢夺协程队列的…...
coco数据集转换SAM2格式
coco是一个大json汇总了所有train的标签 SAM2训练一张图对应一个json标签 import json import os from pycocotools import mask as mask_utils import numpy as np import cv2def poly2mask(points, width, height):points_array np.array(points, dtypenp.int32).reshape(-…...
【CMD、PowerShell和Bash设置代理】
【CMD、PowerShell和Bash设置代理】 1. CMD(命令提示符)临时设置代理(只对当前会话有效):查看当前代理设置:清除临时代理设置:永久设置代理(对所有新的 CMD 会话有效)&am…...
22智能 代码作业集合
3-2 #include <stdio.h>int main() {int a 21;int b 10;int c ;c a b;printf("Line 1 - c 的值是 %d\n", c );c a - b;printf("Line 2 - c 的值是 %d\n", c );c a * b;printf("Line 3 - c 的值是 %d\n", c );c a / b;printf("…...

实现一个简单的后台架子(侧边栏菜单渲染,折叠,黑白主题,组件主题色,全屏,路由快捷栏)
目录 侧边栏菜单渲染 侧边栏折叠 黑白主题 全屏切换 切换组件主题色 tab快捷栏 代码 侧边栏菜单渲染 结合ElementPlus组件库进行实现 新建的Vue3项目,引入了格式化样式normalize.css和ElementPlus,并进行了全局引入 并进行了全局引入 设置高度为100% 粘贴ElementPlus的…...

vue3-canvas实现在图片上框选标记(放大,缩小,移动,删除)
双图版本(模板对比) 业务描述:模板与图片对比,只操作模板框选的位置进行色差对比,传框选坐标位置给后端,返回对比结果显示 draw.js文件: 新增了 createUuid,和求取两个数组差集的方…...

unity3d—demo(2d人物左右移动发射子弹)
目录 人物代码示例: 子弹代码示例: 总结上面代码: 注意点: 人物代码示例: using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerTiao : MonoBehaviour {public f…...
【ETCD】【源码阅读】 深入解析 raftNode.start`函数:Raft 核心启动逻辑剖析
raftNode.start方法 是 etcd 中 Raft 模块的核心启动点,其职责是管理 Raft 状态机的状态变迁、日志处理及集群通信等逻辑。通过对源码的逐行分析,我们将全面揭示其运行机制,探讨其设计背后的分布式系统理念。 函数核心结构 raftNode.start 方…...

Robust Depth Enhancement via Polarization Prompt Fusion Tuning
paper:论文地址 code:github项目地址 今天给大家分享一篇2024CVPR上的文章,文章是用偏振做提示学习,做深度估计的。模型架构图如下 这篇博客不是讲这篇论文的内容,感兴趣的自己去看paper,主要是分享环境&…...

NEFTune,SFT训练阶段给Embedding加噪音
仿照CV里,数据增强的思路(给图像做旋转、反转、改变亮度等);NLP里,SFT训练数据较少时,也可往embedding上加噪音,来增加训练数据的丰富程度。进而提升最终训练效果。 前提假设:Embed…...

uniapp -- 实现页面滚动触底加载数据
效果 首选,是在pages.json配置开启下拉刷新 {"path": "pages/my/document/officialDocument","style": {"navigationStyle":</...
L22.【LeetCode笔记】相交链表(新版)
目录 1.题目 代码模板 2.分析 编辑 算法误区 正确方法1 但不能通过所有的测试用例 修改后 提交结果 正确方法2 节省代码的技巧 1.题目 https://leetcode.cn/problems/3u1WK4/description/ 给定两个单链表的头节点 headA 和 headB ,请找出并返回两个单…...

智能时代网络空间认知安全新观察
文章目录 前言一、历史上的四次认知革命二、人工智能革命掀起认知安全新浪潮三、人工智能技术塑造认知安全新范式四、人工智能治理应对认知安全新思考 前言 12月5日,在2024第三届北外滩网络安全论坛上以“智能时代网络空间认知安全新观察”为主题作主旨演讲&#x…...

游戏如何应对模拟器作弊
模拟器是指能在PC端模拟出安卓手机系统的软件,市面上比较常见的安卓模拟器有:雷电模拟器、MuMu模拟器、夜神模拟器等。 市面上常见的模拟器 模拟器既可以节省手机内存空间,避免长时间玩游戏手机发烫发热的尴尬,也可以用键盘鼠标对…...
c++ 判断一个 IP 地址(可能是 IPv6 或 IPv4)是否属于特定范围
在 C 中,判断一个 IP 地址(可能是 IPv6 或 IPv4)是否属于特定范围时,需要考虑两种不同的地址格式和它们的范围比较。IPv6 和 IPv4 地址结构完全不同,因此需要分别处理这两种地址类型。 实现思路: 识别 IP…...

计算机视觉——相机标定(Camera Calibration)
文章目录 1. 简介2. 原理3. 相机模型3.1 四大坐标系3.2 坐标系间的转换关系3.2.1 世界坐标系到相机坐标系3.2.2 相机坐标系到图像坐标系3.2.3 像素坐标系转换为图像坐标系3.2.4 世界坐标转换为像素坐标 3.3 畸变3.3.1 畸变类型3.3.1.1 径向畸变(Radial Distortion&a…...
【qt环境配置】windows下的qt与vs工具集安装\版本对应关系
vs工具集安装通过vs的在线安装器勾选工具集即可 工具包下载路径:https://www.microsoft.com/zh-cn/download/details.aspx?id40784 配置工具集在qt中可以自动扫描到 《正确在 Windows 上配置 MSVC(2019) 作为 Qt 编译器》https://b3logfile.com/pdf/article/15922…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...

【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...

用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...