位置: IT常识 - 正文

(WebFlux)004、WebFilter踩坑记录

编辑:rootadmin
一、背景 使用SpringWebFlux的WebFilter时,由于不熟悉或一些思考疏忽,容易出现未知的异常。记录一下排查与解决方案,给大家分享一下。 二、问题 2.1 问题描述 在测试接口方法时,出现的错误信息如下(对一些项目路径做了修改): java.lang.IllegalStateExcep ... 一、背景

推荐整理分享(WebFlux)004、WebFilter踩坑记录,希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:,内容如对您有帮助,希望把文章链接给更多的朋友!

使用SpringWebFlux的WebFilter时,由于不熟悉或一些思考疏忽,容易出现未知的异常。记录一下排查与解决方案,给大家分享一下。

二、问题2.1 问题描述

在测试接口方法时,出现的错误信息如下(对一些项目路径做了修改):

java.lang.IllegalStateException: COMPLETEDat org.springframework.http.server.reactive.AbstractListenerReadPublisher$State.subscribe(AbstractListenerReadPublisher.java:451)Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: Error has been observed at the following site(s):*__checkpoint ⇢ springfox.boot.starter.autoconfigure.SwaggerUiWebFluxConfiguration$CustomWebFilter [DefaultWebFilterChain]*__checkpoint ⇢ com.xxx.config.LoginWebFilter$$EnhancerBySpringCGLIB$$f3da6bdf [DefaultWebFilterChain]*__checkpoint ⇢ com.xxx.config.TraceIdFilter [DefaultWebFilterChain]*__checkpoint ⇢ HTTP POST "/abc/test/testMethod" [ExceptionHandlingWebHandler]Original Stack Trace:at org.springframework.http.server.reactive.AbstractListenerReadPublisher$State.subscribe(AbstractListenerReadPublisher.java:451)at org.springframework.http.server.reactive.AbstractListenerReadPublisher.subscribe(AbstractListenerReadPublisher.java:105)2.2 解决问题

通过查看错误信息描述,checkpoint点都在webfilter中,由于对webflux也不是特别熟,所以就只有一个个测试。

通过一系列操作, 把swagger移除,细读TraceIdFilter(内容不多),主要归功于原方案是正确的,修改后错误,最后才定位问题出现在LoginWebFilter。

说说插曲,原实现方式(有阻塞逻辑,没出现上述异常),代码如下:

@Configuration@Slf4j@Order(-10)public class LoginWebFilter implements WebFilter { // 略... @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { ServerHttpRequest request = exchange.getRequest(); if (!enableGateway) { String token = Optional.ofNullable(request.getHeaders().getFirst(Constants.TOKEN)) .orElse(""); // 获取用户信息 User user = getUser(token); if (user != null) { ServerHttpRequest mutateRequest = exchange.getRequest().mutate() .build(); exchange = exchange.mutate().request(mutateRequest).build(); } } return chain.filter(exchange); } private User getUser(String token) { if (StringUtils.isNotBlank(token)) { return redisTemplate.opsForValue().get("xxx:tk:" + token) .flatMap(str -> Mono.justOrEmpty(JsonUtils.toObj(str, User.class))).block(); } return null; }}

这样写,没有复杂的业务逻辑,从上到下,完全OJBK,但是调整后,就出现了上述异常。

改完后的问题代码如下:

// 错误public class LoginWebFilter implements WebFilter {/...略 @Autowired private ReactiveStringRedisTemplate redisTemplate; @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { if (!enableGateway) { ServerHttpRequest request = exchange.getRequest(); String token = Optional.ofNullable(request.getHeaders().getFirst(Constants.TOKEN)) .orElse(""); return getUser(token).flatMap(user -> { ServerHttpRequest mutateRequest = exchange.getRequest().mutate() .header(UserUtils.MEMBER_ID, user.getMemId()) .header(UserUtils.MOBILE, user.getMobile()) .build(); ServerWebExchange newexchange = exchange.mutate().request(mutateRequest).build(); return chain.filter(newexchange); // 问题点 }).switchIfEmpty(chain.filter(exchange)); } return chain.filter(exchange); }// 不在用block private Mono<User> getUser(String token) { if (StringUtils.isNotBlank(token)) { return redisTemplate.opsForValue().get("xxx:tk:" + token) .flatMap(str -> Mono.justOrEmpty(JsonUtils.toObj(str, User.class))); } return Mono.empty(); }}2.3 如何解决

对比改造前和改造后的代码,其实差异不大,那问题出现在哪呢?

由于对webflux也不是特别熟,那就只能一点点试(太蠢了)。 最后发现问题出现在了switchIfEmpty(chain.filter(exchange)),在去掉了switchIfEmpty(chain.filter(exchange)),就不会在出现上述异常。

修改后部分代码如下:

// 半正确@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { if (!enableGateway) { ServerHttpRequest request = exchange.getRequest(); String token = Optional.ofNullable(request.getHeaders().getFirst(Constants.TOKEN)) .orElse(“”); return getUser(token).flatMap(user -> { ServerHttpRequest mutateRequest = exchange.getRequest().mutate() .header(UserUtils.MEMBER_ID, user.getMemId()) .header(UserUtils.MOBILE, user.getMobile()) .build(); ServerWebExchange newexchange = exchange.mutate().request(mutateRequest).build(); return chain.filter(newexchange); }); } return chain.filter(exchange);}

虽然现在不回在出现异常,但是去掉switchIfEmpty后,代码逻辑是不完整的,当获取不到User时,返回Mono.emtpy,那会直接结束流程,不在执行剩下的filter或其他逻辑。真是连环坑,一坑接一坑。所以对代码需要调整一番,调整后如下:

// 有点正确 但是不多@Overridepublic Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { if (!enableGateway) { ServerHttpRequest request = exchange.getRequest(); String token = Optional.ofNullable(request.getHeaders().getFirst(Constants.TOKEN)) .orElse(“”); return getUser(token).switchIfEmpty(Mono.error(() -> new BizException(ErrorCode.USER_IS_NULL_ERROR))) .flatMap(user -> { ServerHttpRequest mutateRequest = exchange.getRequest().mutate() .header(UserUtils.MEMBER_ID, user.getMemId()) .header(UserUtils.MOBILE, user.getMobile()) .build(); ServerWebExchange newexchange = exchange.mutate().request(mutateRequest).build(); return chain.filter(newexchange); }).onErrorResume(e -> chain.filter(exchange)); } return chain.filter(exchange);}(WebFlux)004、WebFilter踩坑记录

当获取用户为空后,抛出异常,然后在兜底,当异常的时候执行chain.filter(exchange)(好蠢的方式.. 但是解决问题了)。

2.4 意外之喜

各位看官,就在我写完上完上面的代码修改方案之后,读了一下修改完后的代码,突然发现问题出在哪了,所以连夜修改了代码方式。现在我听我细细道来。

2.4.1 问题点

原因点:chain.filter(exchange)重复执行

switchIfEmpty(chain.filter(exchange))这个点本意是想用在当getUser 方法为空时,执行其它WebFilter的逻辑,从而不影响主流程。

忽略了一点是:当chain.filter(newexchange)这个方法执行完后,返回的也是Mono<Void>,也是为空。所以无论如何,代码最后的逻辑都会走到switchIfEmpty(chain.filter(exchange))。

但是当getUser获取到用户后,会重复执行chain.filter(exchange),如下

return chain.filter(newexchange)switchIfEmpty(chain.filter(exchange))

由于第一次执行完chain.filter(exchange),request、response都已经关闭,所以出现了xx COMPLETE,那看来的确符合逻辑。

2.4.2 验证猜想

这个验证方式还是挺简单的,那就是分别传入正常的TOKEN和错误的TOKEN。

具体操作:.....(本人已完成)

结论:

当传入错误的token的时候,确实没有抛出异常,完美执行。但是当传入正确的token,出现了熟悉的异常。

2.4.3 代码调整

知道问题的原因,那就好调整代码了。修改后如下:

public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { if (!enableGateway) { ServerHttpRequest request = exchange.getRequest(); String token = Optional.ofNullable(request.getHeaders().getFirst(Constants.TOKEN)) .orElse(request.getHeaders().getFirst("suuid")); return getUser(token).map(user -> { ServerHttpRequest mutateRequest = exchange.getRequest().mutate() .header(UserUtils.MEMBER_ID, user.getMemId()) .header(UserUtils.MOBILE, user.getMobile()) .build(); return exchange.mutate().request(mutateRequest).build(); // 调整当getUser为空时,返回的内容 }).switchIfEmpty(Mono.just(exchange)).flatMap(chain::filter); } return chain.filter(exchange);}

至此,问题就完全解决拉!心里美滋滋!

三、总结

1、遇到问题,还是要多看看呀,细细思考一下

2、多看代码,发现问题,实现完美的解决方案

本文链接地址:https://www.jiuchutong.com/zhishi/310752.html 转载请保留说明!

上一篇:Vue2基于elementUi的多级菜单动态生成(vue+elementui)

下一篇:phpcms控制器在哪(phpcms使用教程)

  • 粤康码亮码失败是什么原因(粤康码亮码失败什么意思)

    粤康码亮码失败是什么原因(粤康码亮码失败什么意思)

  • qq长图怎么弄(qq长图怎么弄好像没有了)

    qq长图怎么弄(qq长图怎么弄好像没有了)

  • 抖音怎么上传几分钟的视频(抖音怎么上传几分钟的完整版视频)

    抖音怎么上传几分钟的视频(抖音怎么上传几分钟的完整版视频)

  • mop是啥(MOP是啥啊)

    mop是啥(MOP是啥啊)

  • 小米10青春版防水吗(小米10青春版防抖吗)

    小米10青春版防水吗(小米10青春版防抖吗)

  • 华为p30录屏怎么录(华为p30录屏怎么录声音)

    华为p30录屏怎么录(华为p30录屏怎么录声音)

  • vivox30手机发热(vivox30手机发热怎么解决)

    vivox30手机发热(vivox30手机发热怎么解决)

  • 华为手机锁屏后网络就断了(华为手机锁屏后自动亮屏怎么解决)

    华为手机锁屏后网络就断了(华为手机锁屏后自动亮屏怎么解决)

  • 微信拉黑后恢复对方知道吗(微信拉黑后恢复了能看到朋友圈吗)

    微信拉黑后恢复对方知道吗(微信拉黑后恢复了能看到朋友圈吗)

  • 把qq卸载了聊天记录还在吗(卸载qq后聊天记录怎么恢复)

    把qq卸载了聊天记录还在吗(卸载qq后聊天记录怎么恢复)

  • 迪优美特网络机顶盒为什么不能用了(迪优美特网络机顶盒刷机教程)

    迪优美特网络机顶盒为什么不能用了(迪优美特网络机顶盒刷机教程)

  • 华为平板学生模式不见了(华为平板学生模式强制破解)

    华为平板学生模式不见了(华为平板学生模式强制破解)

  • 海思kirin980是什么处理器(海思krirn970)

    海思kirin980是什么处理器(海思krirn970)

  • 红米k30需不需要贴膜(红米k30s需要带套吗)

    红米k30需不需要贴膜(红米k30s需要带套吗)

  • 京东红包过期了能恢复吗?(京东红包过期了怎么办)

    京东红包过期了能恢复吗?(京东红包过期了怎么办)

  • 微信朋友圈怎么发长时间的视频(微信朋友圈怎么发文字不发图片)

    微信朋友圈怎么发长时间的视频(微信朋友圈怎么发文字不发图片)

  • 手机淘宝怎么批量收货(手机淘宝怎么批量退款)

    手机淘宝怎么批量收货(手机淘宝怎么批量退款)

  • 华为手环怎么连接手机(华为手环怎么连接oppo手机)

    华为手环怎么连接手机(华为手环怎么连接oppo手机)

  • 被注销的qq号怎么恢复(被注销的QQ号怎么找回来)

    被注销的qq号怎么恢复(被注销的QQ号怎么找回来)

  • 电脑版微信可以视频吗(电脑版微信可以扫一扫二维码吗)

    电脑版微信可以视频吗(电脑版微信可以扫一扫二维码吗)

  • 拼多多会员名怎么看(拼多多会员名怎么修改)

    拼多多会员名怎么看(拼多多会员名怎么修改)

  • pr如何调整分辨率(pr视频的分辨率怎么调整)

    pr如何调整分辨率(pr视频的分辨率怎么调整)

  • 华为水滴屏手机有哪些(华为水滴屏手机有哪些型号)

    华为水滴屏手机有哪些(华为水滴屏手机有哪些型号)

  • 苹果11为什么不支持5g(苹果11为什么不能下载软件)

    苹果11为什么不支持5g(苹果11为什么不能下载软件)

  • 任务群怎么区分会员和商家(任务群怎么区分好坏)

    任务群怎么区分会员和商家(任务群怎么区分好坏)

  • 手机打电话呼叫失败怎么回事(手机打电话呼叫转移怎么取消)

    手机打电话呼叫失败怎么回事(手机打电话呼叫转移怎么取消)

  • qq聊天界面有个耳朵是什么意思(qq聊天界面有个耳朵怎么取消)

    qq聊天界面有个耳朵是什么意思(qq聊天界面有个耳朵怎么取消)

  • ddr4是什么意思(lpddr4是什么意思)

    ddr4是什么意思(lpddr4是什么意思)

  • xmp.exe是什么?xmp.exe崩溃如何解决(xmp是什么格式的文件是一种预设吗)

    xmp.exe是什么?xmp.exe崩溃如何解决(xmp是什么格式的文件是一种预设吗)

  • 新买的笔记本电脑应该注意什么(新买的笔记本电脑需要装系统吗)

    新买的笔记本电脑应该注意什么(新买的笔记本电脑需要装系统吗)

  • 微信小程序实现快速精确定位(微信小程序实现灯泡开关效果)

    微信小程序实现快速精确定位(微信小程序实现灯泡开关效果)

  • 金税盘软件
  • 个人提供劳务报酬需要到税务局开发票吗?
  • 合伙企业需要申报个税吗
  • 合同能源管理项目账务处理
  • 销售企业资金风险点有哪些呢
  • 原材料的归集和整理
  • 客户回款扣除的手续费会计分录怎么做?
  • 冲抵货款的返利怎么做账
  • 申请专利的费用如何入账
  • 融资租赁承租人和出租人的会计处理
  • 建安企业预缴企业所得税税率
  • 地税发票联丢失要补救报帐有何办法?
  • 转账支票必须对着开发票单位吗?
  • 增值税进项税额转出是什么意思
  • 转让非独占许可使用权调整
  • 减免税款交企业所得税吗
  • 发票总金额怎么算折扣
  • 本年固定资产投资额与不良贷款的关系
  • 出口退税和增值税抵扣一样吗
  • 离婚后房产过户需要多少钱
  • 小规模企业记账软件哪个好
  • 建筑行业简易征收税率是5%吗?
  • 收到利息收入会计分录怎么写
  • 企业所得税内部辅助机构说明怎么写
  • 收到科技局研发的短信
  • Win11 Build 22000.132 预览版 ISO 官方镜像下载与安装
  • 贸易公司出口是什么意思
  • linux i
  • 逾期增值税扣税凭证
  • 设备经营租赁属于什么行业
  • 资产负债表的编制方法和步骤
  • 新准则规定
  • Element-Plus el-col、el-row快速布局
  • 手把手教你win7换主板不重装系统的方法
  • 经验模态分解和变分模态分解
  • vue中computed和watch
  • 国税纳税申报表下载
  • 暂未取得发票的费用怎么入账
  • 客户要发票加收怎么办
  • php cms
  • sql server 2008 R2安装
  • hadoop集群状态
  • 减免增值税的账务处理是什么
  • 如何在Access中设置有效性规则必须大于等于0
  • 金税四期对小规模企业有何要求
  • 审计助理是干啥的
  • 固定资产未转固属于什么问题
  • 收到运输服务发票会计分录
  • 收到客户承兑怎么做账
  • 外贸企业留抵退税申请表怎么填
  • 收到技术服务费的账务处理
  • 出差费计入工资总额吗
  • 租房公司报销发票怎么开
  • 行政单位年结
  • 健身中心开的服装店
  • 购入汽车属于什么会计科目
  • sqlserver高级语法
  • sqlserver执行计划走偏
  • 服务器文件夹共享分组
  • 让Windows Server 2008系统安全更上一层楼
  • freebsd怎么样
  • 关于操作系统的叙述中
  • win10家庭版怎么关闭windows defender
  • windows7禁止开机启动
  • win8功能
  • win8突然没有声音
  • vue两个花括号
  • jqueryanimate动画
  • 获取磁盘失败代码0-0
  • android 属性动画改变view大小
  • Android studio DrawerLayout
  • jquery替换div内容
  • android 开发 教程
  • javascript的核心语言对象包括
  • express后端
  • 滴滴发票怎么查行程
  • 文山市税务
  • 郑州房产契税缴纳
  • 税务筹划和纳税申报哪个更容易学
  • 2021税务稽查重点方向
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设