手写VUE后台管理系统10 - 封装Axios实现异常统一处理
目录
- 前后端交互约定
- 安装
- 创建Axios实例
- 拦截器
- 封装请求方法
- 业务异常处理

axios 是一个易用、简洁且高效的http库
axios 中文文档:http://www.axios-js.com/zh-cn/docs/
前后端交互约定
在本项目中,前后端交互统一使用 application/json;charset=UTF-8 的请求方式,后端返回对象统一为如下格式
export interface ResponseBody<T = any> {status: boolean, // 业务处理状态,true表示正常,false表示异常code: string // 业务处理状态码message: string, // 提示信息data?: T // 业务处理返回数据
}
安装
yarn add axios
创建Axios实例
在
src目录下创建http目录,http请求相关的文件都放置于该目录
创建 axios.ts 文件,用于定义 axios
// axios.ts
const instance: AxiosInstance = axios.create({baseURL: import.meta.env.VITE_APP_BASE_API,timeout: 60000,headers: { 'Content-Type': 'application/json;charset=UTF-8' },
})
其中,import.meta.env.VITE_APP_BASE_API 是 .env 中配置的环境变量,不同环境使用不同的请求地址
拦截器
通过 instance.interceptors.request.use 实现前置拦截器,发起请求前执行,用于对请求对象进行加工处理。
下面这段代码主要做的事情就是将 token 设置到请求头中。
// axios.ts
async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise<InternalAxiosRequestConfig> {if (config.modulePrefix) {config.url = config.modulePrefix + config.url}const token = useAuthorization()if (token.value && config.token !== false) {config.headers.set("Authorization", token.value)}console.log("execute http request:" + config.url)return config
}instance.interceptors.request.use(requestHandler)
RequestConfigExtra 为自定义参数,在本项目中定义如下,可根据需要自行扩展。
export interface RequestConfigExtra {// 模块前缀modulePrefix?: string,// 发起请求时,是否需要在请求头中附加 tokentoken?: boolean,// 成功处理函数,默认为 false,如果为 false,则什么都不做,如果为 true,则自动提示成功信息,如果为 Function,则自定义处理结果success?: boolean | ((response: ResponseBody<any>) => void),// 失败处理函数,默认为 true,如果为 false,则什么都不做,如果为 true,则自动提示失败信息,如果为 Function,则自定义处理结果error?: boolean | ((response: ResponseBody<any>) => void),
}
通过 instance.interceptors.response.use 实现后置拦截器,对后端返回数据进行处理。
function responseHandler(response: any): ResponseBody<any> | AxiosResponse<any> | Promise<any> | any {return response.data
}function errorHandler(errorInfo: AxiosError): Promise<any> {if (errorInfo.response) {const { data, status, statusText } = errorInfo.response as AxiosResponse<ResponseBody>if (status === 401) {const token = useAuthorization()token.value = nullmessage.error(data?.message || statusText)router.push({path: '/login', query: { redirect: router.currentRoute.value.fullPath}})} else {message.error(data?.message || statusText)} }return Promise.reject(errorInfo)
}instance.interceptors.response.use(responseHandler, errorHandler)
errorHandler 方法对系统异常进行了统一处理,如果后端返回的 status 不是 200,则会执行该处理方法,如果返回 401,表示没有通过登录鉴权,自动跳转登录页,如果是其它异常码,则提示错误信息。
封装请求方法
这里对 restful 常用的四种请求方式进行进一步的封装
// axios.ts
function instancePromise<R = any, T = any>(options: AxiosRequestConfig<T> & RequestConfigExtra): Promise<ResponseBody<R>> {return new Promise((resolve, reject) => {instance.request<any, ResponseBody<R>>(options).then((res) => {try {resolve(responseBodyHandle(res, options))} catch (err) {reject(err || new Error('response handle error!'))}}).catch((e: Error | AxiosError) => {reject(e)})})
}export function doGet<R = any, T = any>(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,params,method: RequestEnum.GET,...config,}return instancePromise<R, T>(options)
}export function doPost<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.POST,...config,}return instancePromise<R, T>(options)
}export function doPut<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.PUT,...config,}return instancePromise<R, T>(options)
}export function doDelete<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.DELETE,...config,}return instancePromise<R, T>(options)
}
业务异常处理
在拦截器中,我们对系统异常进行了统一处理,在实际项目中,更多的情况是前端请求没有通过后端的业务校验,后端返回错误信息,前端进行提示。
创建一个业务异常类
export class ResponseBodyError extends Error {code: stringmessage: stringcause: anyconstructor({ code, message, cause }: { code: string, message: string, cause?: any }) {super();this.code = code;this.message = message;this.cause = cause}
}
实现业务异常统一处理,通过在请求时定义 RequestConfigExtra 中的参数来实现对后端返回结果的提示。
比如:查询请求,设置为 {success:false, error: true},如果请求失败,提示错误信息,如果请求成功,不作处理。业务请求,设置为 {success: true, error: true},如果请求失败,提示错误信息,如果处理成功,提示操作成功。
function responseBodyHandle<R = any, T = any>(response: ResponseBody<R>, options: AxiosRequestConfig<T> & RequestConfigExtra): any {const { status, message:msg, code, data } = responseconst { success, error } = optionsif (status === true) {if (success === true) {message.success(msg ?? "操作成功")} else if (isFunction(success)) {success(response)}return response} else {if (isFunction(error)) {error(response)} else if (error !== false) {message.error(msg ?? "操作失败")}throw new ResponseBodyError({ code, msg })}
}
完整代码如下:
// axios.ts
/*** 创建 Axios 实例*/
const instance: AxiosInstance = axios.create({baseURL: import.meta.env.VITE_APP_BASE_API,timeout: 60000,headers: { 'Content-Type': 'application/json;charset=UTF-8' },
})/*** 前置拦截器*/
async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise<InternalAxiosRequestConfig> {if (config.modulePrefix) {config.url = config.modulePrefix + config.url}const token = useAuthorization()if (token.value && config.token !== false) {config.headers.set(authorizationHeader, authorizationValue())}console.log("execute http request:" + config.url)return config
}/*** 后置拦截器*/
function responseHandler(response: any): ResponseBody<any> | AxiosResponse<any> | Promise<any> | any {return response.data
}/*** 系统异常统一处理函数*/
function errorHandler(errorInfo: AxiosError): Promise<any> {if (errorInfo.response) {const { data, status, statusText } = errorInfo.response as AxiosResponse<ResponseBody>if (status === 401) {const token = useAuthorization()token.value = nullmessage.error(data?.message || statusText)router.push({path: '/login', query: { redirect: router.currentRoute.value.fullPath}})} else {message.error(data?.message || statusText)} }return Promise.reject(errorInfo)
}instance.interceptors.request.use(requestHandler)
instance.interceptors.response.use(responseHandler, errorHandler)/*** 业务异常统一处理函数*/
function responseBodyHandle<R = any, T = any>(response: ResponseBody<R>, options: AxiosRequestConfig<T> & RequestConfigExtra): any {const { status, message:msg, code, data } = responseconst { success, error } = optionsif (status === true) {if (success === true) {message.success(msg ?? "操作成功")} else if (isFunction(success)) {success(response)}return response} else {if (isFunction(error)) {error(response)} else if (error !== false) {message.error(msg ?? "操作失败")}throw new ResponseBodyError({ code, msg })}
}function instancePromise<R = any, T = any>(options: AxiosRequestConfig<T> & RequestConfigExtra): Promise<ResponseBody<R>> {return new Promise((resolve, reject) => {instance.request<any, ResponseBody<R>>(options).then((res) => {try {resolve(responseBodyHandle(res, options))} catch (err) {reject(err || new Error('response handle error!'))}}).catch((e: Error | AxiosError) => {reject(e)})})
}export function doGet<R = any, T = any>(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,params,method: RequestEnum.GET,...config,}return instancePromise<R, T>(options)
}export function doPost<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.POST,...config,}return instancePromise<R, T>(options)
}export function doPut<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.PUT,...config,}return instancePromise<R, T>(options)
}export function doDelete<R = any, T = any>(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise<ResponseBody<R>> {const options = {url,data,method: RequestEnum.DELETE,...config,}return instancePromise<R, T>(options)
}
相关文章:
手写VUE后台管理系统10 - 封装Axios实现异常统一处理
目录 前后端交互约定安装创建Axios实例拦截器封装请求方法业务异常处理 axios 是一个易用、简洁且高效的http库 axios 中文文档:http://www.axios-js.com/zh-cn/docs/ 前后端交互约定 在本项目中,前后端交互统一使用 application/json;charsetUTF-8 的请…...
JavaScript装饰者模式
JavaScript装饰者模式 1 什么是装饰者模式2 模拟装饰者模式3 JavaScript的装饰者4 装饰函数5 AOP装饰函数6 示例:数据统计上报 1 什么是装饰者模式 在程序开发中,许多时候都我们并不希望某个类天生就非常庞大,一次性包含许多职责。那么我们就…...
C++学习笔记01
01.C概述(了解) c语言在c语言的基础上添加了面向对象编程和泛型编程的支持。 02.第一个程序helloworld(掌握) #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std;//标准命名空间int main() {//co…...
【UE5】初识MetaHuman 创建虚拟角色
步骤 在UE5工程中启用“Quixel Bridge”插件 打开“Quixel Bridge” 点击“MetaHumans-》MetaHuman Presets UE5” 点击“START MHC” 在弹出的网页中选择一个虚幻引擎版本,然后点击“启动 MetaHuman Creator” 等待一段时间后,在如下页面点击选择一个人…...
物流实时数仓:数仓搭建(DWD)一
系列文章目录 物流实时数仓:采集通道搭建 物流实时数仓:数仓搭建 物流实时数仓:数仓搭建(DIM) 物流实时数仓:数仓搭建(DWD)一 文章目录 系列文章目录前言一、文件编写1.目录创建2.b…...
MATLAB安装
亲自验证有效,多谢这位网友的分享: https://blog.csdn.net/xiajinbiaolove/article/details/88907232...
C语言——预处理详解(#define用法+注意事项)
#define 语法规定 #define定义标识符 语法: #define name stuff #define例子 #include<stdio.h> #define A 100 #define STR "abc" #define FOR for(;;)int main() {printf("%d\n", A);printf("%s\n", STR);FOR;return 0; } 运行结果…...
Linux(23):Linux 核心编译与管理
编译前的任务:认识核心与取得核心原始码 Linux 其实指的是核心。这个【核心(kernel)】是整个操作系统的最底层,他负责了整个硬件的驱动,以及提供各种系统所需的核心功能,包括防火墙机制、是否支持 LVM 或 Quota 等文件系统等等&a…...
Oracle RAC环境下redo log 文件的扩容
环境: 有一个2节点RAC每一个节点2个logfile group每一个group含2个member每一个member的大小为200M 目标:将每一个member的大小有200M扩充到1G。 先来看下redo log的配置: SQL> select * from v$log;GROUP# THREAD# SEQUENCE# …...
Java入门学习笔记一
一、Java语言环境搭建 1、JAVA语言的跨平台原理 1.1、什么是跨平台性? 跨平台就是说,同一个软件可以在不同的操作系统(例如:Windows、Linux、mad)上执行,而不需要对软件做任务处理。即通过Java语言编写的…...
分布式块存储 ZBS 的自主研发之旅|元数据管理
重点内容 元数据管理十分重要,犹如整个存储系统的“大黄页”,如果元数据操作出现性能瓶颈,将严重影响存储系统的整体性能。如何提升元数据处理速度与高可用是元数据管理的挑战之一。SmartX 分布式存储 ZBS 采用 Log Replication 的机制&…...
六大设计原则
六大设计原则 1、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 2、开放封闭原则 规定软件中的对象、类、模块和函数对扩展应该是开放的,对于修改应该是封闭的。用抽象定义结构,用具体实现扩展细节。 3、里氏替换原则 如果S是T的子类型…...
dockerfile创建镜像 lNMP+wordpress
dockerfile创建镜像 lNMPwordpress nginx dockernginx mysql dockermysql php dockerphp nginx vim nginx.conf vim Dockerfile docker network create --subnet172.17.0.0/16 --opt "com.docker.network.bridge.name""docker1" mynetwork docker buil…...
深入理解——快速排序
目录 💡基本思想 💡基本框架 💡分割方法 ⭐Hoare版本 ⭐挖坑法 ⭐前后指针法 💡优化方法 ⭐三数取中法 ⭐小区间内使用插入排序 💡非递归实现快速排序 💡性能分析 💡基本思想 任取待排…...
【代码随想录】算法训练计划50
dp 1、123. 买卖股票的最佳时机 III 题目: 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意:你不能同时参与多笔交易(你必须在再次购…...
【数据分享】2019-2023年我国区县逐年二手房房价数据(Excel/Shp格式)
房价是一个区域发展程度的重要体现,一个区域的房价越高通常代表这个区域越发达,对于人口的吸引力越大!因此,房价数据是我们在各项城市研究中都非常常用的数据!之前我们分享了2019—2023年我国区县逐月的二手房房价数据…...
Redis设计与实现之整数集合
目录 一、内存映射数据结构 二、整数集合 1、整数集合的应用 2、数据结构和主要操作 3、intset运行实例 创建新intset 添加新元素到 intset 添加新元素到 intset(不需要升级) 添加新元素到 intset (需要升级) 4、升级 升级实例 5、关于升级 …...
[Kubernetes]2. k8s集群中部署基于nodejs golang的项目以及Pod、Deployment详解
一. 创建k8s部署的镜像 1.部署nodejs项目 (1).上传nodejs项目到节点node1 (2).压缩nodejs项目 (3).构建nodejsDockerfile 1).创建nodejsDockerfile 具体可参考:[Docker]十.Docker Swarm讲解,在/root下创建nodejsDockerfile,具体代码如下: FROM node #把压缩文件COPY到镜像的…...
讯飞星火大模型api调用
讯飞星火大模型,通过websocket方式通信传递协议要求的报文,然后将流式返回的报文拼接为完整的响应内容,status2时是最后一条消息。因为是websocket方式所以是异步响应的,如果想要同步需要使用CountDownLatch控制下线程等待最后一条…...
TCP与UDP:网络世界中的“顺丰快递”与“广播电台”
随着互联网的普及,我们每天都在与网络打交道。而在这背后,数据的传输离不开TCP和UDP这两种传输协议。它们就像网络世界中的“顺丰快递”和“广播电台”,各自有着不同的工作方式和特点。让我们一起来了解一下它们吧! 一、TCP&…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...
初学 pytest 记录
安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
