位置: 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使用教程)

  • App推广的10大难题,量上不去有时候不是你的错(app推广难不难)

    App推广的10大难题,量上不去有时候不是你的错(app推广难不难)

  • 纽曼蓝牙耳机怎么配对(纽曼蓝牙耳机怎么重置)

    纽曼蓝牙耳机怎么配对(纽曼蓝牙耳机怎么重置)

  • 微信点在看别人能看到吗(微信点在看别人会知道吗)

    微信点在看别人能看到吗(微信点在看别人会知道吗)

  • 电脑登录qq显示不能重复登录(电脑登录qq显示版本过低怎么办)

    电脑登录qq显示不能重复登录(电脑登录qq显示版本过低怎么办)

  • ctrl键加什么是截图

    ctrl键加什么是截图

  • 怎么设置禁止境外来电(怎么设置禁止境外来电移动)

    怎么设置禁止境外来电(怎么设置禁止境外来电移动)

  • 腾讯视频会员老是掉线怎么办(腾讯视频会员老是重新登录)

    腾讯视频会员老是掉线怎么办(腾讯视频会员老是重新登录)

  • 手机屏幕变色了咋回事(水进手机屏幕变色了)

    手机屏幕变色了咋回事(水进手机屏幕变色了)

  • 小米收不到短信验证码(小米13收不到短信怎么回事)

    小米收不到短信验证码(小米13收不到短信怎么回事)

  • 惠普打印机加墨后 还是提示不足(惠普打印机加墨教程)

    惠普打印机加墨后 还是提示不足(惠普打印机加墨教程)

  • 手机电池温度45度正常吗(手机电池温度45度)

    手机电池温度45度正常吗(手机电池温度45度)

  • 苹果设置来电关机状态(苹果设置来电关闭闪光灯)

    苹果设置来电关机状态(苹果设置来电关闭闪光灯)

  • 红米note8pro6G和8G区别大么(红米note8pro6g和8g区别)

    红米note8pro6G和8G区别大么(红米note8pro6g和8g区别)

  • 微信如何设置自动回复功能(微信如何设置自动抢红包功能)

    微信如何设置自动回复功能(微信如何设置自动抢红包功能)

  • a1634是苹果什么型号(a1634是什么型号的)

    a1634是苹果什么型号(a1634是什么型号的)

  • 苹果f开头是哪里生产(苹果f开头的是什么机子)

    苹果f开头是哪里生产(苹果f开头的是什么机子)

  • 怎么统一更改数字字体(excel如何统一修改数字)

    怎么统一更改数字字体(excel如何统一修改数字)

  • 苹果11可以放两张移动卡吗(苹果11可以放两张联通卡吗)

    苹果11可以放两张移动卡吗(苹果11可以放两张联通卡吗)

  • 美图秀秀改照片kb大小(美图秀秀改照片背景颜色)

    美图秀秀改照片kb大小(美图秀秀改照片背景颜色)

  • 无互联网连接是啥意思(无互联网连接是哪出问题)

    无互联网连接是啥意思(无互联网连接是哪出问题)

  • 转转如何取消实人认证(转转怎样取消实名认证)

    转转如何取消实人认证(转转怎样取消实名认证)

  • 优酷3倍播放怎么弄(优酷长摁三倍播放)

    优酷3倍播放怎么弄(优酷长摁三倍播放)

  • 一加7pro支不支持红外(一加7 pro可以用5g吗)

    一加7pro支不支持红外(一加7 pro可以用5g吗)

  • 快手发现怎么换类型(快手发现怎么换成精选)

    快手发现怎么换类型(快手发现怎么换成精选)

  • 微信如何支付钱给好友(微信如何支付钱给商家二维码)

    微信如何支付钱给好友(微信如何支付钱给商家二维码)

  • 爱奇艺如何注销账号(爱奇艺如何注销手机号绑定)

    爱奇艺如何注销账号(爱奇艺如何注销手机号绑定)

  • 资本公积转增资本会引起什么变化
  • 营业外收入需要结转到本年利润吗
  • 其他应付款是不是长期负债
  • 收到投资款怎么做会计凭证
  • 转登记为小规模纳税人政策
  • 商场积分兑换现金怎么用
  • 代开建安发票怎么做账务处理?
  • 出售自建厂房的税率
  • 超过离线开票限定时长09d11f怎么解决
  • 2021年新疆果业灰枣销售情况
  • 营改增之后账务怎么处理
  • 新购进的固定资产可以一次性抵扣
  • 一般空调安装费多少钱
  • 物业公司广告位出租怎么入账
  • 商标设计人享有著作吗
  • 建筑工程购买的家用清洁电器能勾选认证吗
  • 材料没入库的会计分录
  • 增值税红字发票申报表怎么填
  • win10最新版本22h2激活
  • 外贸企业出口退税计算
  • 小规模纳税人缴纳增值税怎么算
  • win11好用吗知乎
  • 世界上最早的数码相机
  • 会计账簿登记错误怎么办
  • php处理数组的函数
  • 分支机构分摊税款的计算
  • 非上市公司股权估值
  • 污水处理增值税税率
  • php获取文件后缀名的方法
  • 两套账目
  • 2022年终总结
  • id命令的哪个参数可显示用户账号的uid信息
  • vuecli怎么使用自定义组件
  • 资产负债率 70%
  • 预收账款需要申请吗
  • 应收账款收不回来
  • 邀请客户参加会议
  • 报账单大写金额负数填写方式
  • 免征增值税的会计处理
  • 家具厂成本
  • 固定资产累计折旧计算公式
  • 公对公打款发票
  • 已入库的原材料会计分录
  • 个人咨询服务费个税怎么算
  • 增值税普通发票几个点
  • 什么是四大行业
  • 税控盘的会计分录怎么做
  • 材料暂估分录
  • 废品损失如何处理
  • 同比增长怎么算出来的
  • MSSQL 2005/2008 日志压缩清理方法小结
  • sql语句优化总结
  • SQL Server中通过reverse取某个最后一次出现的符号后面的内容(字符串反转)
  • mysql_info
  • windows虚拟内存转移有什么危害
  • 重装win7系统后鼠标反应慢
  • 电脑爆音卡死
  • gentoo安装教程2021
  • Linux系统复制图片
  • centos coreos
  • 让mac桌面变整洁的方法
  • winxp系统开机启动项
  • 怎么删除隐藏文件夹win 10
  • win10系统怎么找到我的电脑
  • win8.1应用商店
  • win8.
  • windows10x预览版
  • windows 10 mobile--移动版
  • w10系统如何
  • 用bat打开cmd执行命令
  • bat 远程连接
  • js过滤filter
  • nodejs lua
  • jquery操作表单
  • 江苏省全电发票开通流程
  • 北京市税务总局官网
  • 在深圳居住的香港居民怎样办理边境地区通行证
  • 事业单位大额资金拨付需要什么报账材料
  • 浙江省国税局地址
  • 超期未申报还能申报吗
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设