不建议用生成器 throw() 方法动态报错降级,因其非标准实践且依赖生成器内部异常处理;应改用装饰器统一捕获异常并转换为标准降级响应,或通过 close() + finally 实现安全终止与兜底。

在自定义防腐网关中,不建议直接使用生成器的 throw() 方法来“动态报错并降级”。这不是标准实践,也违背生成器设计初衷——throw() 是用于向生成器内部注入异常、由生成器自身决定是否捕获或传播,而非作为外部主动触发降级的契约机制。
理解 throw() 的真实作用
throw() 本质是向生成器暂停点(如 yield 处)抛入一个异常,能否转化为“降级”取决于生成器内部是否捕获该异常并返回兜底值。它不是网关层可控的标准化降级入口。
- 生成器若未用
try/except捕获传入的异常,会直接中断并向上冒泡,导致调用方收到原始异常,无法统一拦截 - 即使生成器内部处理了
throw()异常,其返回值仍需显式yield或return,不能自动映射为网关定义的降级响应结构 - 不同生成器对同一异常类型的处理逻辑可能不一致,难以形成可复用的降级契约
推荐替代方案:用装饰器封装生成器 + 统一异常拦截
真正可行的做法,是在防腐网关层对生成器做包装,通过装饰器统一捕获异常,并按预设规则转换为标准降级响应(如空对象、缓存值、默认 DTO)。
- 定义降级契约接口,例如
fallback: Callable[[], Any]或配置化降级策略(HTTP 状态码、重试次数、熔断阈值) - 装饰器内调用生成器时用
try...except捕获业务异常(如ServiceUnavailable、TimeoutError),再调用fallback() - 生成器本身保持纯净,只负责核心逻辑;降级决策完全由网关装饰器控制,与迭代器生命周期解耦
若必须与生成器交互,用 close() + 自定义上下文管理更安全
当需要提前终止生成器并触发清理或降级逻辑时,优先使用 close() 触发 GeneratorExit,并在生成器内用 finally 块执行兜底动作。
-
close()是生成器协议明确支持的协作式终止方式,语义清晰、行为确定 - 可在
finally中写入日志、上报指标、返回默认值,比依赖throw()更可靠 - 网关可在超时或熔断时主动
close()生成器,再构造标准降级响应,避免异常穿透
防腐网关真正的降级契约应独立于迭代器机制
标准降级契约(如 OpenFeign 的 @FallbackFactory、Sentinel 的 blockHandler)都基于方法调用模型,而非生成器状态机。防腐网关应将生成器视为一种数据源实现,其降级应发生在“调用入口”或“结果消费环节”,而非干预生成器内部执行流。
- 把生成器包装成类似
Supplier<stream>></stream>或Callable<iterator>></iterator>,网关统一处理创建和消费阶段的异常 - 消费端(如 WebFlux 的
Flux.fromIterable())天然支持 onErrorResume、onErrorReturn,更适合对接降级逻辑 - 保持生成器职责单一,降级逻辑集中、可测、可配置,不分散在每个
yield点











