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

【深入解析spring cloud gateway】07 自定义异常返回报文

Servlet的HttpResponse对象,返回响应报文,一般是这么写的,通过输出流直接就可以将返回报文输出。

OutputStream out = response.getOutputStream();
out.write("输出的内容");
out.flush();

在filter中如果发生异常(例如请求参数不合法),抛出异常信息的时候,调用方收到的返回码和body都是Spring Cloud Gateway框架处理来处理的。这一节我们分析一下,gateway的异常返回报文是怎么返回的,并定义一个自己的异常返回报文格式。

一、先定义一个Filter,直接抛出异常

定义一个直接抛出异常的filter

public class ExceptionFilter implements GlobalFilter, Ordered {@Override    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {throw new IllegalArgumentException("参数不合法");    }@Override    public int getOrder() {return 0;    }
}

异常抛出如下图
在这里插入图片描述

json内容如下:

{"timestamp": "2023-08-28T03:55:02.380+00:00","path": "/hello-service/hello","status": 500,"error": "Internal Server Error","requestId": "0204dca5-1"
}

二、源码分析

上节我们分析了核心流程。在整个核心流程中,我们并没有关注有异常的情况。
入口HttpWebHandlerAdapter调用的delegate实际上就是:DefaultErrorWebExceptionHandler
在这里插入图片描述

代码如下:

@Override
public Mono<Void> handle(ServerHttpRequest request, ServerHttpResponse response) {//省略部分代码return getDelegate().handle(exchange).doOnSuccess(aVoid -> logResponse(exchange)).onErrorResume(ex -> handleUnresolvedError(exchange, ex)).then(Mono.defer(response::setComplete));
}

进入DefaultErrorWebExceptionHandler的handle方法,分析见注释

@Override
public Mono<Void> handle(ServerWebExchange exchange) {Mono<Void> completion;try {//正常的处理流程completion = super.handle(exchange);}catch (Throwable ex) {completion = Mono.error(ex);}
//产生异常的情况,由异常处理器来进行处理for (WebExceptionHandler handler : this.exceptionHandlers) {completion = completion.onErrorResume(ex -> handler.handle(exchange, ex));}return completion;
}

如果产生异常的情况,由异常处理器来进行处理,这个异常处理器是一个列表。
而异常处理器最核心的就是这个:DefaultErrorWebExceptionHandler
其handle方法如下

@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {if (exchange.getResponse().isCommitted() || isDisconnectedClientError(throwable)) {return Mono.error(throwable);}this.errorAttributes.storeErrorInformation(throwable, exchange);ServerRequest request = ServerRequest.create(exchange, this.messageReaders);return getRoutingFunction(this.errorAttributes).route(request).switchIfEmpty(Mono.error(throwable)).flatMap((handler) -> handler.handle(request)).doOnNext((response) -> logError(request, response, throwable)).flatMap((response) -> write(exchange, response));
}

跟到getRoutingFunction里面看看

@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {return route(acceptsTextHtml(), this::renderErrorView).andRoute(all(), this::renderErrorResponse);
}

最终跟到下面的这个方法:renderErrorResponse,从下面的截图可以看到,error Map这个对象,正是报文体的格式
在这里插入图片描述

如果我们想自定义一个异常响应的返回报文,如下,应该怎么弄呢?

{"returnCode": "ERROR","errorMsg": "参数异常","body": null
}

我们实际上可以继承DefaultErrorWebExceptionHandler,并且实现其renderErrorResponse方法就可以了。
可以看到DefaultErrorWebExceptionHandler,是通过下面的方式注入到容器的,如果我们也定义一个也注册到容器,那么就会覆盖原有的实现
在这里插入图片描述

整体流程图如下:

在这里插入图片描述

三、自定义异常处理器

1、定义一个产生异常的filter,模拟产生异常

@Slf4j
public class ExceptionFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {log.info("filter产生了异常");throw new IllegalArgumentException("参数不合法");}@Overridepublic int getOrder() {return 0;}
}

2、自定义异常处理器

/*** 自定义异常处理器*/
public class CustomErrorWebExceptionHandler extends DefaultErrorWebExceptionHandler {public CustomErrorWebExceptionHandler(ErrorAttributes errorAttributes, WebProperties.Resources resources, ErrorProperties errorProperties, ApplicationContext applicationContext) {super(errorAttributes, resources, errorProperties, applicationContext);}@Overrideprotected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {// 最终是用responseBodyMap来生成响应body的Map<String, Object> responseBodyMap = new HashMap<>();// 这里和父类的做法一样,取得DefaultErrorAttributes整理出来的所有异常信息Map<String, Object> error = getErrorAttributes(request, getErrorAttributeOptions(request, MediaType.ALL));// 原始的异常信息可以用getError方法取得Throwable throwable = getError(request);responseBodyMap.put("returnCode", "my error code");responseBodyMap.put("errorMsg", throwable.getMessage());responseBodyMap.put("body", null);return ServerResponse// http返回码.status(HttpStatus.INTERNAL_SERVER_ERROR)// 类型和以前一样.contentType(MediaType.APPLICATION_JSON)// 响应body的内容.body(BodyInserters.fromValue(responseBodyMap));}
}

3、注册异常处理器

@Configuration(proxyBeanMethods = false)
public class ExceptionHandlerConfig {private final ServerProperties serverProperties;public ExceptionHandlerConfig(ServerProperties serverProperties) {this.serverProperties = serverProperties;}@Beanpublic ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes,WebProperties webProperties, ObjectProvider<ViewResolver> viewResolvers,ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) {CustomErrorWebExceptionHandler exceptionHandler = new CustomErrorWebExceptionHandler(errorAttributes,webProperties.getResources(), this.serverProperties.getError(), applicationContext);exceptionHandler.setViewResolvers(viewResolvers.orderedStream().collect(Collectors.toList()));exceptionHandler.setMessageWriters(serverCodecConfigurer.getWriters());exceptionHandler.setMessageReaders(serverCodecConfigurer.getReaders());return exceptionHandler;}
}

4、请求效果
在这里插入图片描述

相关文章:

【深入解析spring cloud gateway】07 自定义异常返回报文

Servlet的HttpResponse对象&#xff0c;返回响应报文&#xff0c;一般是这么写的&#xff0c;通过输出流直接就可以将返回报文输出。 OutputStream out response.getOutputStream(); out.write("输出的内容"); out.flush();在filter中如果发生异常&#xff08;例如…...

如何写一个sh脚本将一个本地文件通过 scp命令上传到远程的 centos服务器?

如何写一个sh脚本将一个本地文件通过 scp命令上传到远程的 centos服务器&#xff1f; 1.1 背景需求1.2 解决方案1.3 附录1.3.1 scp命令用法与示例1.3.1.1 scp命令用法与解释1.3.1.2 scp 命令用法示例1.3.1.2.1 示例一&#xff1a;从本地复制文件到远程计算机1.3.1.2.2 示例二&a…...

【CMake工具】工具CMake编译轻度使用(C/C++)

目录 CMake编译工具 一、CMake概述 二、CMake的使用 2.1 注释 2.1.1 注释行 2.1.2 注释块 2.2 源文件 2.1.1 共处一室 2.1.2 VIP包房 2.3 私人定制 2.2.1 定义变量 2.2.2 指定使用的C标准 2.2.3 指定输出的路径 2.4 搜索文件 2.3.1 方式1 2.3.2 方式2 2.5 包含…...

用Navicat备份Mysql演示系统数据库的时候出:Too Many Connections

今天用Navicat进行数据备份的时候&#xff0c;发现由于数据库连接数目过多导致连接锁定&#xff0c;这种情况在多人协同开发的场景中很常见。当然我这里也因为多个应用使用了数据库连接&#xff0c;所以出现了Too Many Connections。 可能是超过最大连接数了。 1、进入Navicat…...

知识储备--基础算法篇-矩阵

2.矩阵 2.1第54题螺旋矩阵 第一题上来就跪了&#xff0c;看了官方答案感觉不是很好理解&#xff0c;找了一个比较容易理解的。 class Solution(object):def spiralOrder(self, matrix):""":type matrix: List[List[int]]:rtype: List[int]"""…...

Zabbix -- QQ邮箱报警

目录 一、创建监控项及触发器 1.1创建监控项 1.2 创建监控项的触发器 1.3 测试触发器 二、邮箱媒介设置 2.1 设置报警媒介类型 2.2 创建用户群组和用户 三、动作绑定 3.1 创建动作 3.2 动作操作 3.3 动作测试&#xff08;发送邮件测试&#xff09; 四、问题总结 4.1 邮件发送…...

eclipse链接MySQL数据库

在MySQL官网下载驱动 MySQLhttps://www.mysql.com/cn/点击下载&#xff1a; 页面滚动到最下方选择社区版&#xff1a; 选择Java版本: 接下来&#xff0c;需要选择操作系统&#xff0c;我们选择平台独立&#xff1a; eclipse 接下来&#xff0c;我们打开eclipse&#xff0c;新建…...

ansible 使用roles简单部署LAMP平台

目录 一、了解roles目录 二、基于构建LAMP平台创建roles目录 1、在192.168.115.148创建目录 2、书写php的测试页面 3、编写httpd角色的main.yml文件 4、编写mysql角色的main.yml文件 6、编写lamp的playbook 7、启动剧本 8、访问 一、了解roles目录 在Ansible中&#…...

如何使用Web Storage对页面中数据进行监听?

当使用Web Storage存储的数据发生变化时&#xff0c;会触发Window对象的storage事件&#xff0c;我们可以监听该事件并指定事件处理函数&#xff0c;当其他页面中的localStorage或 sessionStorage中保存的数据发生改变时&#xff0c;就会执行事件处理函数。 监听storage事件的…...

GO语言网络编程(并发编程)runtime包

GO语言网络编程&#xff08;并发编程&#xff09;runtime包 1. runtime包 1.1.1. runtime.Gosched() 让出CPU时间片&#xff0c;重新等待安排任务(大概意思就是本来计划的好好的周末出去烧烤&#xff0c;但是你妈让你去相亲,两种情况第一就是你相亲速度非常快&#xff0c;见…...

MR源码解析和join案例

MR源码解析 new Job(): 读取本地文件, xml配置job.start(): 启动线程job的run():线程方法 runTasks(): 传入对应的接口&#xff0c;启动map或者reduceMapTask类的run(): 设置map阶段的参数&#xff0c;初始化任务&#xff0c;创建上下文对象 创建读取器LineRecordReader判断是…...

ML+LLMs:利用LLMs大语言模型赋能或者结合ML机器学习算法进行具体应用的简介、具体案例之详细攻略

ML+LLMs:利用LLMs大语言模型赋能或者结合ML机器学习算法进行具体应用的简介、具体案例之详细攻略 目录 利用LLMs赋能或者结合ML算法进行具体应用的简介...

python GIL锁

1、GIL是什么 GIL&#xff1a;Global Interpreter Lock又称全局解释器锁。简单来说是一个互斥锁&#xff0c;每个线程在执行的过程中都需要先获取GIL&#xff0c;作用就是限制多线程同时执行&#xff0c;使得在同一进程内任何时刻仅有一个线程在执行。 由于GIL的存在&#xff0…...

git打tag和版本控制规范

我们在开发中经常会遇到要打tag的情况&#xff0c;但这个tag应该如何打呢&#xff1f;我不知道大家平时是怎么打的&#xff0c;但我基本就是从1.0.0开始进行往上递增&#xff0c;至于如何递增&#xff0c;基本凭感觉。今天同事新打了一个tag进行发版&#xff0c;然后被架构点名…...

php版 短信跳转微信小程序

实现这功能首先&#xff0c;小程序端添加业务域名 php代码 <?php declare (strict_types1);namespace app\controller\Admin;use app\model\Set; use app\Request;class Admin_Url_Scheme {public function getScheme(Request $request) {$appid 小程序appid;$secret 小…...

leetcode127单词接龙刷题打卡

127. 单词接龙 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 每一对相邻的单词只差一个字母。对于 1 < i < k 时&#xff0c;每个 si 都在 wordList 中。注意&am…...

基于SSM的物流管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

EagleSDR USB HAT FT600

给EagleSDR做了个USB 3.0的子卡&#xff0c;采用FT600方案&#xff0c;实物如下&#xff1a; 用FT600DataStreamerDemoApp测试&#xff0c;速度如下&#xff1a; 由于FT600是16bit的接口&#xff0c;如果用FT601的32bit接口&#xff0c;性能应该还会有大幅提升。 测试代码很简…...

Java多线程(四)锁策略(CAS,死锁)和多线程对集合类的使用

锁策略&#xff08;CAS&#xff0c;死锁&#xff09;和多线程对集合类的使用 锁策略 1.乐观锁VS悲观锁 2.轻量级锁VS重量级锁 3.自旋锁VS挂起等待锁 4.互斥锁VS读写锁 5.可重入锁vs不可重入锁 死锁的第一种情况 死锁的第二种情况 死锁的第三种情况 CAS 1.实现原子类 …...

基于spring boot+ vue+ mysql开发的UWB室内外定位系统源码

现代制造业厂区面积大、人员数量多、物资设备不断增加&#xff0c;随着工业信息化技术的发展&#xff0c;大型制造企业中对人员、车辆、物资的管理要求越来越细致。 高精度定位管理系统使用UWB室内定位技术&#xff0c;通过在厂区安装定位基站&#xff0c;为人员或设备佩戴定位…...

5分钟精通网页内容转化:AnythingLLM浏览器扩展全攻略

5分钟精通网页内容转化&#xff1a;AnythingLLM浏览器扩展全攻略 【免费下载链接】anything-llm 这是一个全栈应用程序&#xff0c;可以将任何文档、资源&#xff08;如网址链接、音频、视频&#xff09;或内容片段转换为上下文&#xff0c;以便任何大语言模型&#xff08;LLM&…...

Meixiong Niannian画图引擎Typora集成:Markdown文档图像生成

Meixiong Niannian画图引擎Typora集成&#xff1a;Markdown文档图像生成 1. 为什么文档作者需要在Typora里直接画图&#xff1f; 你有没有过这样的经历&#xff1a;写技术文档时&#xff0c;突然需要一张示意图来说明某个流程&#xff1b;写产品需求时&#xff0c;想快速画个…...

socat-windows:开发者与管理员必备的跨平台数据转发工具

socat-windows&#xff1a;开发者与管理员必备的跨平台数据转发工具 【免费下载链接】socat-windows unofficial windows build of socat http://www.dest-unreach.org/socat/ 项目地址: https://gitcode.com/gh_mirrors/so/socat-windows 在网络调试与数据传输领域&…...

英语体育比赛口语

一、看比赛1. 邀约看球中文英文今晚有比赛&#xff0c;一起看吗&#xff1f;Theres a game tonight. Want to watch together?你看了昨晚的比赛吗&#xff1f;Did you watch the game last night?决赛什么时候&#xff1f;When is the final?我们去酒吧看球吧&#xff01;Le…...

2024网安保研上岸图鉴:从211边缘到清北直博的破局之路

1. 边缘人的逆袭起点&#xff1a;认清定位比盲目努力更重要 作为西北某211计算机大类边缘专业的学生&#xff0c;我的起点可以说毫无优势。专业名称听着像计算机&#xff0c;实际课程设置却偏向传统工科&#xff1b;学院往届最优秀的学长也只止步华五&#xff1b;我的编程能力在…...

数据中心升级选卡指南:Intel X710 vs. Mellanox MCX4121A,10G网卡实战对比与避坑心得

数据中心网络升级实战&#xff1a;Intel X710与Mellanox MCX4121A深度评测与选型策略 当数据中心面临网络升级时&#xff0c;10G双端口网卡的选择往往成为关键决策点。作为基础设施的核心组件&#xff0c;网卡性能直接影响虚拟化效率、存储吞吐和业务连续性。本文将基于实际部署…...

为什么你的单细胞数据需要sctransform?Seurat标准化方法对比

为什么你的单细胞数据需要sctransform&#xff1f;深度解析标准化方法的技术革命 单细胞RNA测序技术正在重塑我们对生命复杂性的理解。当研究人员第一次看到单细胞数据中那些令人眼花缭乱的基因表达矩阵时&#xff0c;往往会面临一个关键问题&#xff1a;如何从这些充满技术噪音…...

标签噪声鲁棒训练:从理论到实践,构建深度学习模型的抗噪防线

1. 标签噪声&#xff1a;深度学习中的隐形杀手 第一次用MNIST数据集跑分类模型时&#xff0c;我发现哪怕故意把20%的标签打乱&#xff0c;模型在测试集上依然能达到85%以上的准确率。这个结果让我误以为深度神经网络对标签噪声天然具有免疫力——直到后来在医疗影像分类项目里…...

5步打造高效音乐体验:Listen1扩展的智能选择与效率提升指南

5步打造高效音乐体验&#xff1a;Listen1扩展的智能选择与效率提升指南 【免费下载链接】listen1_chrome_extension one for all free music in china (chrome extension, also works for firefox) 项目地址: https://gitcode.com/gh_mirrors/li/listen1_chrome_extension …...

家庭实验室方案:树莓派控制OpenClaw调用远程Qwen3-32B服务

家庭实验室方案&#xff1a;树莓派控制OpenClaw调用远程Qwen3-32B服务 1. 为什么选择树莓派OpenClaw组合 去年冬天&#xff0c;当我试图用语音控制家里的智能设备时&#xff0c;发现市面上的解决方案要么需要持续联网&#xff08;隐私堪忧&#xff09;&#xff0c;要么响应延…...