当前位置: 首页 > news >正文

从一个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 || '商品编号已存在')}
}

错误提示重复的原因

  1. 后端返回数据:{code: 0, msg: “商品编号已存在”, data: null}
  2. 响应拦截器发现 code !== 1,显示错误消息并 reject
  3. 业务代码的 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 {// 问题已经被前台处理了,你不用管
}

响应拦截器就像这个"前台接待",它在服务器响应返回到我们的业务代码之前对所有响应进行统一的处理

为什么需要响应拦截器?

  1. 没有响应拦截器时:
// 每个业务请求都需要重复处理这些情况
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) {// 又要重复上面的代码...}
}
  1. 使用响应拦截器后:
// 统一的响应处理
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) {// 错误已经在拦截器中处理过了}
}

四、请求流程图

请求发起 → 请求拦截器 → 服务器 → 响应拦截器 → 业务代码

五、最佳实践总结

  1. 响应拦截器职责
    • 统一处理响应数据格式
    • 统一处理错误提示
    • 处理特殊状态码(如401未登录)
    • 转换服务端数据结构(如果需要)
  2. 业务代码职责
    • 关注业务逻辑
    • 处理成功场景
    • 可以选择性地处理特定错误
    • 不重复错误提示
  3. 错误处理原则
    • 统一入口处理错误
    • 避免重复提示
    • 提供清晰的错误信息
    • 合理使用 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实现在图片上框选标记(放大,缩小,移动,删除)

双图版本&#xff08;模板对比&#xff09; 业务描述&#xff1a;模板与图片对比&#xff0c;只操作模板框选的位置进行色差对比&#xff0c;传框选坐标位置给后端&#xff0c;返回对比结果显示 draw.js文件&#xff1a; 新增了 createUuid&#xff0c;和求取两个数组差集的方…...

unity3d—demo(2d人物左右移动发射子弹)

目录 人物代码示例&#xff1a; 子弹代码示例&#xff1a; 总结上面代码&#xff1a; 注意点&#xff1a; 人物代码示例&#xff1a; using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerTiao : MonoBehaviour {public f…...

【ETCD】【源码阅读】 深入解析 raftNode.start`函数:Raft 核心启动逻辑剖析

raftNode.start方法 是 etcd 中 Raft 模块的核心启动点&#xff0c;其职责是管理 Raft 状态机的状态变迁、日志处理及集群通信等逻辑。通过对源码的逐行分析&#xff0c;我们将全面揭示其运行机制&#xff0c;探讨其设计背后的分布式系统理念。 函数核心结构 raftNode.start 方…...

Robust Depth Enhancement via Polarization Prompt Fusion Tuning

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

NEFTune,SFT训练阶段给Embedding加噪音

仿照CV里&#xff0c;数据增强的思路&#xff08;给图像做旋转、反转、改变亮度等&#xff09;&#xff1b;NLP里&#xff0c;SFT训练数据较少时&#xff0c;也可往embedding上加噪音&#xff0c;来增加训练数据的丰富程度。进而提升最终训练效果。 前提假设&#xff1a;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 &#xff0c;请找出并返回两个单…...

智能时代网络空间认知安全新观察

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

游戏如何应对模拟器作弊

模拟器是指能在PC端模拟出安卓手机系统的软件&#xff0c;市面上比较常见的安卓模拟器有&#xff1a;雷电模拟器、MuMu模拟器、夜神模拟器等。 市面上常见的模拟器 模拟器既可以节省手机内存空间&#xff0c;避免长时间玩游戏手机发烫发热的尴尬&#xff0c;也可以用键盘鼠标对…...

c++ 判断一个 IP 地址(可能是 IPv6 或 IPv4)是否属于特定范围

在 C 中&#xff0c;判断一个 IP 地址&#xff08;可能是 IPv6 或 IPv4&#xff09;是否属于特定范围时&#xff0c;需要考虑两种不同的地址格式和它们的范围比较。IPv6 和 IPv4 地址结构完全不同&#xff0c;因此需要分别处理这两种地址类型。 实现思路&#xff1a; 识别 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 径向畸变&#xff08;Radial Distortion&a…...

【qt环境配置】windows下的qt与vs工具集安装\版本对应关系

vs工具集安装通过vs的在线安装器勾选工具集即可 工具包下载路径&#xff1a;https://www.microsoft.com/zh-cn/download/details.aspx?id40784 配置工具集在qt中可以自动扫描到 《正确在 Windows 上配置 MSVC(2019) 作为 Qt 编译器》https://b3logfile.com/pdf/article/15922…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径

目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

3403. 从盒子中找出字典序最大的字符串 I

3403. 从盒子中找出字典序最大的字符串 I 题目链接&#xff1a;3403. 从盒子中找出字典序最大的字符串 I 代码如下&#xff1a; class Solution { public:string answerString(string word, int numFriends) {if (numFriends 1) {return word;}string res;for (int i 0;i &…...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

认识CMake并使用CMake构建自己的第一个项目

1.CMake的作用和优势 跨平台支持&#xff1a;CMake支持多种操作系统和编译器&#xff0c;使用同一份构建配置可以在不同的环境中使用 简化配置&#xff1a;通过CMakeLists.txt文件&#xff0c;用户可以定义项目结构、依赖项、编译选项等&#xff0c;无需手动编写复杂的构建脚本…...