abortcontroller本身不支持熔断,需叠加状态机实现:独立维护open/half_open/closed状态,区分aborterror与业务错误,滑动窗口计数失败,并按api路径隔离熔断器。

AbortController 本身不支持熔断,必须自己叠加状态管理
AbortController 只负责中止单次请求,没有失败计数、时间窗口、恢复策略这些熔断器必需的能力。直接用 abort() 并不能让后续请求自动跳过或降级——你得在它外面包一层状态机。
典型错误是把 AbortController 当成熔断开关:比如“请求失败就调 abort()”,结果下一次请求照常发出去,完全没触发熔断逻辑。
- 熔断状态(
OPEN/HALF_OPEN/CLOSED)必须独立维护,建议用闭包或 class 实例持有 - 每次请求前先检查熔断状态;若为
OPEN,直接 reject 并跳过fetch调用 -
AbortController只在CLOSED或HALF_OPEN状态下才创建并传入fetch - 超时、网络错误、非 2xx 响应都应计入失败计数,但 401/403 这类业务错误通常不应触发熔断
熔断器需定义明确的失败阈值与冷却时间
没有量化规则的“自动熔断”等于没熔断。常见配置组合:连续 3 次失败(failureThreshold = 3)、5 秒冷却(timeoutMs = 5000)、半开探测间隔 10 秒(halfOpenIntervalMs = 10000)。
这些值不是拍脑袋定的:短于后端服务平均恢复时间,会导致频繁误熔断;太长则失去保护意义。建议从 failureThreshold=3、timeoutMs=3000 起步,在真实流量下观察日志调整。
-
timeoutMs是熔断器进入OPEN后拒绝所有请求的持续时间,不是请求超时 -
halfOpenIntervalMs是从OPEN切到HALF_OPEN的等待时长,期间只放行一个试探请求 - 失败计数应带滑动窗口(如最近 10 秒内),避免历史抖动影响当前判断;简单实现可用数组 +
Date.now()过滤
fetch 请求必须同时处理 abort 和熔断 reject
网关返回的 Promise 可能因三种原因拒绝:被 AbortController.abort() 中止、熔断器主动 reject、fetch 自身抛错(如网络中断)。这三者要区分对待,尤其不能把 AbortError 当作业务失败计入熔断。
if (err.name === 'AbortError') {
// 不计入失败计数,不更新熔断状态
throw err;
}
// 其他错误才调用 this.recordFailure()
- 用
err.name === 'AbortError'判断是否由abort()引起,这是最可靠方式 - 不要依赖
err.message.includes('aborted'),不同浏览器 message 格式不一致 - 熔断 reject 应带自定义 error name(如
MeltedError),方便上层做差异化兜底 - 若请求已发出但响应未返回时触发熔断(如
HALF_OPEN下试探失败),需显式调controller.abort()避免悬挂
并发请求下熔断状态必须线程安全
多个请求几乎同时到达时,若共享同一熔断器实例,可能多个请求都进入 HALF_OPEN 并发试探,导致后端压力突增。必须确保半开状态下仅允许一个请求通过。
常见漏洞是用 if (state === HALF_OPEN) { state = CLOSED; doRequest() } 这种非原子操作——两个请求读到同一状态,都执行了 doRequest()。
- 用
Promise.resolve().then(() => {...})或queueMicrotask做简易协调,但更稳妥的是加锁标志位(如isHalfOpenProbing = true) - 试探请求成功后,必须重置失败计数且同步切回
CLOSED;失败则重置计时器并维持OPEN - 避免在
finally块里修改状态,因为 abort 和网络错误都会进finally,容易误恢复
/api/users 和 /api/orders 各自独立熔断),否则一个接口雪崩会拖垮整个网关。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










