[Spring Cloud] (2)gateway全局异常捕捉统一返回值

文章目录

    • 处理转发失败的情况
    • 全局参数
    • 同一返回格式
      • 操作消息对象AjaxResult
      • 返回值状态描述对象AjaxStatus
      • 返回值枚举接口层StatusCode
    • 全局异常处理器
    • 自定义通用异常
      • 定一个自定义异常
      • 覆盖默认的异常处理
      • 自定义异常处理工具

在上一篇章时我们有了一个简单的gateway网关
[Spring Cloud] gateway简单搭建与请求转发-CSDN博客
现在我们需要根据这个网关进行一部分的改进

现在我们需要进一步的处理一些问题,来使得网关更加完善。
本篇文章的完整代码文件已放置在gitee。
杉极简/gateway网关阶段学习

处理转发失败的情况

正常情况下,我们请求了一个接口,并得到了一个结果,如下:
image.png
但是,我们依然要考虑,如果访问到一个不存在的接口,会得到什么样的结果?
如果不做任何修改的时候,我们会得到以下的结果:
image.png
但这不是我们想要的。
我们想要如下返回结果。
image.png
因此我们需要配置一个全局异常处理器来处理。
为达到这个目的,我们开始构建一些基础的功能,描述如下。

全局参数

我们需要去创建一个全部配置,如下所示:
这里统一存放着我们需要读取的配置,主要为全局使用的参数。具体配置方式如下所示:
在网关项目中创建一个config文件夹,用于存放网关的相关配置。(当然,能想做网关的人,应该都熟练的会使用Spring Boot了,在Spring Boot项目中,这都是一些较为基础的内容)
此时,我们先配置一个全局异常捕捉-打印堆栈异常的参数,用于本文的一些功能当中。
image.png

global:# 全局异常捕捉-打印堆栈异常printStackTrace: true
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;/*** @author fir* @date 2023/7/28 17:53*/
@Data
@Component
@ConfigurationProperties(prefix = "global")
public class GlobalConfig {/*** 全局异常捕捉-打印堆栈异常*/private boolean printStackTrace;
}

image.png

同一返回格式

创建一个result文件夹,用于存放统一返回值的相关配置
该部分比较基础,暂时只说明配置方式与代码。
image.png

操作消息对象AjaxResult

import java.io.Serializable;
import java.util.HashMap;/*** 操作消息-JSON** @author fir*/
public class AjaxResult extends HashMap<String, Object> implements Serializable {private static final long serialVersionUID = 1L;/*** 状态码*/public static final String CODE_TAG = "code";/*** 返回内容*/public static final String MSG_TAG = "msg";/*** 数据对象*/public static final String DATA_TAG = "data";/*** 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。*/public AjaxResult() {}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg  状态描述*/public AjaxResult(int code, String msg) {super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象** @param code 状态码* @param msg  状态描述* @param data 数据对象*/public AjaxResult(int code, String msg, Object data) {super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (data != null) {super.put(DATA_TAG, data);}}/*** 返回成功消息** @return 成功消息*/public static AjaxResult success() {AjaxStatus success = AjaxStatus.SUCCESS;return AjaxResult.success(success.getCode(), success.getMsg());}/*** 返回成功数据** @return 成功消息*/public static AjaxResult success(Object data) {AjaxStatus success = AjaxStatus.SUCCESS;return AjaxResult.success(success.getMsg(), data);}/*** 返回成功数据** @return 成功消息*/public static AjaxResult success(AjaxStatus success) {return AjaxResult.success(success.getMsg(), new HashMap<>(0));}/*** 返回成功消息** @param code 状态吗* @param msg  状态描述* @return 消息体*/public static AjaxResult success(Integer code, String msg) {return new AjaxResult(code, msg);}/*** 返回成功消息** @param msg  状态描述* @param data 数据对象* @return 成功消息*/public static AjaxResult success(String msg, Object data) {AjaxStatus success = AjaxStatus.SUCCESS;return new AjaxResult(success.getCode(), msg, data);}/*** 返回特定状态描述** @param statusCode 特定的枚举结果* @param data       数据对象* @return 请求结果*/public static AjaxResult success(StatusCode statusCode, Object data) {return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), data);}/*** 返回错误消息** @return 警告消息*/public static AjaxResult error() {return AjaxResult.error(AjaxStatus.LOSE_OPERATION.getMsg());}/*** 返回错误消息** @param msg 状态描述* @return 警告消息*/public static AjaxResult error(String msg) {return AjaxResult.error(msg, new HashMap<>(0));}/*** 返回错误消息** @param msg  状态描述* @param data 数据对象* @return 警告消息*/public static AjaxResult error(String msg, Object data) {AjaxStatus loseEfficacy = AjaxStatus.LOSE_EFFICACY;return new AjaxResult(loseEfficacy.getCode(), msg, data);}/*** 返回错误消息** @param code 状态码* @param msg  状态描述* @return 警告消息*/public static AjaxResult error(int code, String msg) {return new AjaxResult(code, msg, new HashMap<>(0));}/*** 返回特定状态描述** @param statusCode 特定的枚举结果* @param data       数据对象* @return 请求结果*/public static AjaxResult error(StatusCode statusCode, Object data) {return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), data);}/*** 返回特定状态描述** @param statusCode 特定的枚举结果* @return 请求结果*/public static AjaxResult error(StatusCode statusCode) {return new AjaxResult(statusCode.getCode(), statusCode.getMsg(), new HashMap<>(0));}
}

返回值状态描述对象AjaxStatus

import lombok.Getter;/*** 返回值状态与描述* * @author fir*/@Getter
public enum AjaxStatus implements StatusCode {/*** 请求成功*/SUCCESS(200, "请求成功"),/*** 登录成功*/SUCCESS_LOGIN(200, "登录成功"),/*** 登出成功*/SUCCESS_LOGOUT(200, "登出成功"),/*** 启动成功*/SUCCESS_FLOW_START(200, "启动成功"),/*** 暂无数据*/NO_DATA(200, "暂无数据"),/*** 错误请求*/BAD_REQUEST(400, "错误请求"),/*** 登录过期*/EXPIRATION_TOKEN(401, "登录过期"),/*** 服务不存在*/FAILED_SERVICE_DOES(404, "服务不存在"),/*** 账号或密码为空*/NULL_LOGIN_DATA(480, "账号或密码为空"),/*** 建立通信-通信建立失败*/FAILED_COMMUNICATION(481, "通信建立失败"),/*** 接口不存在*/NULL_API(404, "接口不存在"),/*** 建立通信-非法请求*/ILLEGAL_REQUEST(482, "非法请求"),/*** 请求失败*/LOSE_EFFICACY(490, "请求失败"),/*** 操作失败*/LOSE_OPERATION(491, "操作失败"),/*** 请求失败*/FAILED(500, "请求失败"),/*** 服务不可用(gateway网关总定义-所有未定义处理的异常都返回该异常)*/SERVICE_UNAVAILABLE(500, "服务不可用"),/*** 请求整体加密-无效会话*/SESSION_INVALID(601, "无效会话"),/*** 请求整体加密-会话过期*/SESSION_EXPIRE(602, "会话过期"),/*** 防重放校验失败*/ANTI_REPLAY_VERIFY_FAILED(701, "防重放校验失败"),/*** 防重放校验失败*/INTEGRITY_VERIFY_FAILED(801, "完整性校验失败"),/*** 预留*/PASS(1000, "请求失败");private final int code;private final String msg;AjaxStatus(int code, String msg) {this.code = code;this.msg = msg;}
}

返回值枚举接口层StatusCode

package com.fir.gateway.config.result;/*** 返回值枚举接口层* @author 18714*/
public interface StatusCode {/*** 获取code信息** @return code码*/int getCode();/*** 获取msg信息** @return msg描述*/String getMsg();
}

全局异常处理器

做两步

  1. 覆盖默认的异常处理。
  2. 自定义异常处理。

自定义通用异常

通常的处理过程为抛出异常->全局异常捕捉->返回前端
通常在代码中,对于某个特定的条件,我们抛出一个自定义异常,并携带特定的状态码与状态描述

if (session == null) {throw new CustomException(AjaxStatus.SESSION_INVALID);
}

而此时,我们在开发环境中通常需要显示堆栈异常,但是生成环境中,大多数是不需要的,此时我们就是用了全局参数配置在自定义异常工具这个类中,我们配置了定义异常默认不打印堆栈异常

定一个自定义异常

import com.fir.gateway.config.result.AjaxStatus;
import lombok.Getter;/*** 自定义通用异常* 抛出异常->全局异常捕捉->返回前端** @author fir*/
@Getter
public class CustomException extends RuntimeException {/*** code状态码*/private final int code;/*** 错误状态码*/private final AjaxStatus ajaxStatus;public CustomException(AjaxStatus ajaxStatus) {super(ajaxStatus.getMsg());this.code = ajaxStatus.getCode();this.ajaxStatus = ajaxStatus;}}

覆盖默认的异常处理

此时我们覆盖默认的异常处理,并使用自定义的异常处理工具JsonExceptionHandler

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;import java.util.Collections;
import java.util.List;/*** 覆盖默认的异常处理* @author fir*/
@Configuration
@EnableConfigurationProperties({ServerProperties.class, WebProperties.class})
public class ErrorHandlerConfiguration {private final ServerProperties serverProperties;private final ApplicationContext applicationContext;private final WebProperties webProperties;private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public ErrorHandlerConfiguration(ServerProperties serverProperties,WebProperties webProperties,ObjectProvider<List<ViewResolver>> viewResolversProvider,ServerCodecConfigurer serverCodecConfigurer,ApplicationContext applicationContext) {this.serverProperties = serverProperties;this.applicationContext = applicationContext;this.webProperties = webProperties;this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {JsonExceptionHandler exceptionHandler = new JsonExceptionHandler(errorAttributes,this.webProperties,this.serverProperties.getError(),this.applicationContext);exceptionHandler.setViewResolvers(this.viewResolvers);exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());return exceptionHandler;}}

自定义异常处理工具

解决三个问题

  1. 处理自定义异常
  2. 处理不存在的接口
  3. 对于其他的异常,统一返回一个指定的错误描述AjaxStatus.SERVICE_UNAVAILABLE
package com.fir.gateway.config.exception;import com.fir.gateway.config.GlobalConfig;
import com.fir.gateway.config.result.AjaxResult;
import com.fir.gateway.config.result.AjaxStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;import javax.annotation.Resource;/*** 自定义异常处理工具* 异常时用JSON代替HTML异常信息** @author fir*/
@Slf4j
public class JsonExceptionHandler extends DefaultErrorWebExceptionHandler {/*** 网关参数配置*/@Resourceprivate GlobalConfig globalConfig;public JsonExceptionHandler(ErrorAttributes errorAttributes, WebProperties webProperties, ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, webProperties.getResources(), errorProperties, applicationContext);log.info(String.valueOf(errorProperties));log.info(String.valueOf(errorAttributes));}/*** 重构方法,设置返回属性格式*/@Overrideprotected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {Throwable errorThrowable = getError(request);// 自定义异常默认不打印堆栈异常// 决定是否打印堆栈异常boolean printStackTrace = globalConfig.isPrintStackTrace();if (printStackTrace) {errorThrowable.printStackTrace();}// 打印全局异常log.error(errorThrowable.getMessage());Class<?> errorClass = errorThrowable.getClass();String simpleName = errorClass.getSimpleName();AjaxStatus ajaxStatus;switch (simpleName) {case "CustomException":// 处理自定义异常CustomException customException = (CustomException) errorThrowable;ajaxStatus = customException.getAjaxStatus();break;case "NotFoundException":case "ResponseStatusException":// 处理404ajaxStatus = AjaxStatus.NULL_API;break;default:// 统一返回一个服务错误描述ajaxStatus = AjaxStatus.SERVICE_UNAVAILABLE;break;}AjaxResult result = AjaxResult.error(ajaxStatus);return ServerResponse.status(200).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(result));}
}

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

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

相关文章

docker 安装 nginx + httpd + php-fpm

原文地址&#xff1a;http://www.taoluyuan.com/index.php/archives/30/#2 展示 1.安装 1.1安装docker 1.2安装nginx 1.3安装apache-httpd 1.4安装php-fpm 2.配置nginx反向代理 httpdphp-fmp 1.安装 1.1安装docker 移除旧的版本&#xff1a; sudo yum remove docker 安装…

启动nginx时报错:signal process started

解决方案&#xff0c;直接使用该命令启动&#xff0c;指向nginx.conf配置文件&#xff1a; nginx -c /www/wdlinux/nginx/conf/nginx.conf 启动成功&#xff1a;

产生死锁的四个必要条件

产生死锁的四个必要条件 互斥使用: 一个资源每次只能被一个线程使用。这意味着如果一个线程已经获取了某个资源&#xff08;比如锁&#xff09;&#xff0c;那么其他线程就必须等待&#xff0c;直到该线程释放资源。 不可抢占: 已经获得资源的线程在释放资源之前&#xff0c;不…

[尚硅谷flink] 检查点笔记

在Flink中&#xff0c;有一套完整的容错机制来保证故障后的恢复&#xff0c;其中最重要的就是检查点。 文章目录 11.1 检查点11.1.1 检查点的保存1&#xff09;周期性的触发保存2&#xff09;保存的时间点3&#xff09;保存的具体流程 11.1.2 从检查点恢复状态11.1.3 检查点算法…

如何在Windows安装LocalSend并结合内网穿透实现公网跨平台远程文件互传

文章目录 1. 在Windows上安装LocalSend2. 安装Cpolar内网穿透3. 公网访问LocalSend4. 固定LocalSend公网地址 本篇文章介绍在Windows中部署开源免费文件传输工具——LocalSend&#xff0c;并且结合cpolar内网穿透实现公网远程下载传输文件。 localsend是一款基于局域网的文件传…

【菜狗学前端】原生Ajax笔记(包含原生ajax的get/post传参方式、返回数据等)

这回图片少&#xff0c;给手动替换了~祝看得愉快&#xff0c;学的顺畅&#xff01;哈哈 一 原生ajax经典四步 (一) 原生ajax经典四步 第一步&#xff1a;创建网络请求的AJAX对象&#xff08;使用XMLHttpRequest&#xff09; JavaScript let xhr new XMLHttpRequest() 第二…

【C语言】简易版扫雷+进阶版扫雷

目录 前言 一、分模块化 二、准备雷盘 2.1 游戏菜单 2.2 创建雷盘思路 2.3 构建雷盘 2.4 雷盘展示 2.4.1 初始化雷盘 2.4.2 打印雷盘 三、排雷 3.1 布置雷 3.2 排查雷 四、进阶版扫雷 总结 前言 C语言实现扫雷小游戏&#xff0c;帮我们更进一步的掌握数组、模块化…

bugku-web-decrypt

这里的提示解密后没有什么意义 这里下载文件包 得到一个index.php文件 得到代码 <?php function encrypt($data,$key) {$key md5(ISCC);$x 0;$len strlen($data);$klen strlen($key);for ($i0; $i < $len; $i) { if ($x $klen){$x 0;}$char . $key[$x];$x1;}for…

鸿蒙开发快速入门

基本概念 ArkTS 因为ArkTS是基于Type Script扩展而来&#xff0c;是Type Script的超集&#xff0c;所以也可以关注一下Type Script的语法来理解ArkTS的语法 ArkUI HarmonyOS提供了一套UI开发框架&#xff0c;即方舟开发框架&#xff08;ArkUI框架&#xff09;。方舟开发框架…

k8s:kubectl 命令设置简写启用自动补全功能

k8s&#xff1a;kubectl 命令设置简写&启用自动补全功能 1、设置kubectl命令简写2、启用kubectl自动补全功能 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; Kubernetes&#xff08;K8s&#xff09;是一个强大的容器编排平台&#xff0…

MES管理系统在人工智能方面的应用

为了加强生产管理&#xff0c;提升企业管理水平&#xff0c;制造业之中的很多企业都运用的MES生产管理系统&#xff0c;借以提高对生产车间的监管。那么&#xff0c;MES系统应用的哪些技术&#xff0c;可以促使生产管理变得简单呢?其核心技术主要有以下几个方面。 1、过程控制…

Linux配置程序后台运行(前后台来回切换)

Linux配置程序后台运行 在日常开发过程中&#xff0c;会遇到我们在前台运行程序&#xff0c;此时我们临时有事&#xff0c;但不能关闭终端&#xff0c;否则程序就会在电脑熄屏&#xff08;终端session断开后&#xff09;停止运行。 那么作为一个合格的开发&#xff0c;就必须要…