在微服务架构中,服务间调用出现异常是常见的场景。通常我们希望服务 B 抛出的业务异常能够被服务 A 捕获并向调用方(如网关或前端)正确返回。
然而,在最近的实践中遇到这样的问题:
调用链路Gateway → A服务 → B服务
当 B 服务抛出自定义业务异常 ServiceException 时,A 服务却没有正常解析,而是抛出了 org.apache.dubbo.remoting.RemotingException,最终导致接口返回了非预期结果。

一、问题现象

在 B 服务抛出异常时,A 服务日志出现了典型的 Dubbo 协议层反序列化异常:
Dubbo 在反序列化返回结果时失败,没有正确还原业务异常对象。

二、代码背景

自定义业务异常

Dubbo 配置(关键部分)

由于屏蔽了默认的 ExceptionFilter,我们使用了自定义 MyDubboExceptionFilter 来处理异常透传。

自定义 ExceptionFilter(核心逻辑)

核心逻辑是 透传自定义异常 ServiceException,避免被包装成 RuntimeException
主要逻辑与官方的 ExceptionFilter 区别不大,主要是添加了自定义上下文的处理。 https://github.com/apache/dubbo/blob/dubbo-3.2.0/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/filter/ExceptionFilter.java
理论上应该可以在消费端还原 ServiceException,但实际却失败了。

三、初步排查

起初怀疑是 序列化协议不兼容,尝试了强制指定 Hessian2、Fastjson2 等序列化协议,结果都一样失败 → 排除协议问题。
接着检查了 ServiceException 的定义,也未发现会导致反序列化失败的明显问题。

四、根因定位

在日志中发现关键提示:
然后查找dubbo官方文档,发现是 Dubbo 出于安全考虑,默认启用了序列化安全校验
ServiceException 由于未被加入允许反序列化的白名单,导致被拒绝,从而触发了 Response data error
 
根据官方文档,Dubbo 的 序列化安全机制 有如下几个关键点:
知识点
官方说明 / 行为细节
对应风险或影响
引入历史
Dubbo 3.1.6 引入类校验机制。3.1 默认 WARN,3.2 默认 STRICT
升级版本后若未处理白名单,自定义异常无法透传。
模式选择
STRICT:严格拒绝未允许类;WARN:记录警告但可能尝试反序列化;DISABLE:完全关闭检查。
建议生产用 STRICT + allowlist。
Serializable 校验
配置 dubbo.application.check-serializable=true 时,未实现 Serializable 的类也可能失败。
自定义异常类最好实现 Serializable
自动信任机制
autoTrustSerializeClass + trustSerializeClassLevel 可自动扫描并信任类。
多模块场景下可能失效。
配置文件位置
allowlist 文件路径:resources/security/serialize.allowlist。优先级:用户 > 框架内置 > 自动扫描。
打包时需确认资源文件被正确加载。
社区已知问题
WARN 模式下部分情况仍报错;Jar 包中白名单文件被覆盖问题。
升级或部署时需特别关注。
⚠️ 序列化安全机制的设计初衷是为了防止反序列化漏洞(例如 RCE),避免恶意 Provider 传递不安全类。
 

五、复现 Demo

通过简单的 provider/consumer 调用,可以稳定复现该问题:
消费者日志:
说明 Dubbo 将异常对象视为普通 Map 处理,未能反序列化为 ServiceException

六、解决方案

根据 Dubbo 官方文档,目前有两种解决方式:

方案一:禁用序列化安全检查

日志中会看到:
此时,异常可以正常透传,还原为 ServiceException
⚠️ 缺点:降低了安全性,不推荐在生产环境全局禁用。

方案二:将自定义异常加入白名单(推荐)

resources 下新建配置文件:
启动时 Dubbo 会读取白名单并允许反序列化该类:
此方式更安全,且粒度可控,推荐在生产环境使用。

七、总结

本次问题的根因在于 Dubbo 3.x 引入了序列化安全机制,默认使用 STRICT 模式,禁止反序列化未显式允许的类。
解决思路有两种:
  1. 快速解决:禁用序列化安全检查(开发/测试环境可用)。
  1. 最佳实践:将自定义异常加入 serialize.allowlist 白名单(推荐生产使用)。
这样,服务间调用时,自定义业务异常才能被正确透传与还原,避免出现协议层的反序列化错误。

📎 参考资料

 
 
 
K8s + Spring Cloud + Druid + MySQL 环境下的 Communications Link Failure 问题全解析从零搭建 GitLab + Runner:完整自建 CI/CD 环境实战指南
Loading...