手写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)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/265606.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《opencv实用探索·十六》opencv直方图计算calcHist函数解析

直方图理解&#xff1a; &#xff08;对于8位灰度图像亮度/灰度为(0-255)&#xff0c;12位灰度图像亮度/灰度为(0-4095)&#xff09; 以8位图像为例&#xff0c;亮度分为0到255共256个数值&#xff0c;数值越大&#xff0c;代表的亮度越高。其中0代表纯黑色的最暗区域&#xff…

Linux_CentOS_7.9 VNC安装卸载以及相关配置开机自启动服务简易记录

VNC安装卸载以及相关配置开机自启动服务&#xff1a; 查看环境&#xff1a;&#xff08;yum镜像源配置可以参考我之前文章里面有详细参考http://t.csdnimg.cn/mzGoI&#xff09; [rootorcl238 ~]# rpm -qa | grep vnc ##查看系统现有VNC软件版本 gtk-vnc2-0.7.0-3.el7.x86…

〖Python网络爬虫实战㊷〗- 极验滑块介绍(四)

订阅&#xff1a;新手可以订阅我的其他专栏。免费阶段订阅量1000 python项目实战 Python编程基础教程系列&#xff08;零基础小白搬砖逆袭) 说明&#xff1a;本专栏持续更新中&#xff0c;订阅本专栏前必读关于专栏〖Python网络爬虫实战〗转为付费专栏的订阅说明作者&#xff1…

在前端开发中,什么是SEO(Search Engine Optimization)?如何优化网站的SEO?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

泰裤辣!!!我又学到了监控服务器的各种方法!

好耶&#xff01;又能学习到监控服务器的各种方法了。像是利用linux命令去监控的方法就有好几种哦 方法一&#xff1a;动态监控top命令 方法二&#xff1a;内存监控free -m 方法三&#xff1a;磁盘iostat -d 2 3 还有利用jmeter插件去监控服务器哦我们可以使用ServerAgent插件…

为什么字符串一旦创建就不可以改变了么?

今天看到一个String和StringBuilder的题&#xff0c;很是恼怒&#xff01; 总结下吧。 判断string类创建后可以被修改&#xff08;&#xff09; 理解&#xff1a; 字符串的值一旦被创建&#xff0c;就不能改变指的是字符串的内容不能发生改变。而不是字符串的引用不能发生改…

数据结构与算法—递归及其应用(八皇后,小球出迷宫)

递归 文章目录 递归1.递归应用场景2.递归的概念3.递归调用机制4.递归能解决什么问题5.递归需要遵守的重要规则6.递归-迷宫、八皇后问题6.1 迷宫问题6.2 八皇后问题 1.递归应用场景 迷宫问题(回溯)&#xff0c;递归(Recursion) 2.递归的概念 简单的说&#xff1a;递归就是方法自…

AMEYA360:大唐恩智浦荣获 2023芯向亦庄 “汽车芯片50强”

2023年11月28日&#xff0c;由北京市科学技术委员会和北京市经济和信息化局指导、北京经济技术开发区管理委员会主办、盖世汽车协办的“芯向亦庄”汽车芯片大赛在北京亦庄成功闭幕。 在本次大赛中 大唐恩智浦的 电池管理芯片DNB1168 (应用于新能源汽车BMS系统) 凭卓越的性能及高…

AidLux:手机/平板上的Linux环境与AI开发利器

AidLux是一个基于ARM架构的跨生态&#xff08;鸿蒙/AndroidLinux&#xff09;一站式智能物联网&#xff08;AIoT&#xff09;应用开发和部署平台&#xff0c;正受到越来越多开发者和用户的青睐。既可以作为手机/平板上的一个Linux环境使用&#xff0c;也可以作为AI开发利器以发…

HCIA-H12-811题目解析(5)

1、【单选题】 以下关于Hybrid端口说法正确的有&#xff1f; 2、【单选题】使用命令"vlan batch 10 20"和"valn batch 10 to 20"&#xff0c;分别能创建的vlan数量是&#xff1f;&#xff08;&#xff09; 3、【单选题】二层ACL的编号范围是&#xff1f;…

厘米级高精度定位系统为什么更倾向于UWB技术?

超宽带&#xff08;Ultra Wide-Band&#xff0c;UWB&#xff09;是一种新型的无线通信技术&#xff0c;根据通信委员会的规范&#xff0c;UWB的工作频带为3.1~10.6GHz&#xff0c;系统-10dB带宽与系统中心频率之比大于20%或系统带宽至少为500MHz。 UWB信号的发生可通过发射时间…

Java预科知识

以下内容是根据狂神的Java说、chatgpt和csdn相关博客&#xff0c;结合自己的理解完成的。 Java了解 基于Java 开发了巨多的平台&#xff0c;系统&#xff0c;工具 构建工具&#xff1a; Ant, Maven, Jekins应用服务器&#xff1a;Tomcat, Jetty, Jboss, Websphere, weblogic…