在微服务架构中,服务间调用出现异常是常见的场景。通常我们希望服务 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 的 序列化安全机制 有如下几个关键点:
知识点 | 官方说明 / 行为细节 | 对应风险或影响 |
引入历史 | 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 模式,禁止反序列化未显式允许的类。解决思路有两种:
- 快速解决:禁用序列化安全检查(开发/测试环境可用)。
- 最佳实践:将自定义异常加入
serialize.allowlist白名单(推荐生产使用)。
这样,服务间调用时,自定义业务异常才能被正确透传与还原,避免出现协议层的反序列化错误。
📎 参考资料
- 作者:Yibin
- 链接:https://yibin.dev/article/24560b50-99a4-8009-84da-d55a0e53747d
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章







