事件与 payload 参考
本页是 logger 事件和 notify payload 的单一事实源。其它页面通过链接引用此处。
📋 Logger 事件目录
所有治理行为先归一化为标准 LogEvent,再由你配置的 logger 决定去向(默认 console)。标准事件结构见 消息与日志系统。
| 事件名 | 等级 | 触发能力 | 说明 |
|---|---|---|---|
duplicate.triggered | warn | duplicate | 命中重复请求(ignore / block / reuse)时触发 |
retry.scheduled | info | retry | 一次失败被判定为可重试,下一次 attempt 已安排等待时触发 |
retry.exhausted | warn | retry | retry 生命周期停止时触发(不只是次数用尽,见下方 reason 字段) |
circuitBreaker.blocked | warn | circuitBreaker | 请求被熔断拦截(熔断打开状态)时触发 |
circuitBreaker.stateChange | warn | circuitBreaker | 熔断状态在 NORMAL / CIRCUIT_BREAKER / HALF_OPEN 间切换时触发 |
circuitBreaker.halfOpenProbe | info | circuitBreaker | 半开状态放行试探请求时触发 |
circuitBreaker.recovered | info | circuitBreaker | 半开试探成功、熔断单元恢复到 NORMAL 时触发 |
requestGuard.internalError | error | 守护层自身 | 守护层内部异常被隔离时触发;生产环境静默,仅走 logger |
duplicate.triggered
js
{
level: 'warn',
event: 'duplicate.triggered',
message: '请勿重复提交(第2次)',
namespace: 'requestGuard',
timestamp: 1717315200000,
data: {
strategy: 'ignore',
capability: 'duplicate',
config: { /* 原始请求配置 */ },
options: { /* 当前生效的 duplicate 配置 */ },
requestKey: 'post_/api/submit_...',
key: 'post_/api/submit_...', // requestKey 的别名
debugInfo: { /* 标识生成依据,用于排查误判 */ },
firstStack: '...', // 首次请求调用栈(captureStack 开启时)
duplicateStack: '...', // 重复请求调用栈
stack: '...', // duplicateStack 的别名
repeatCount: 2,
pendingCount: 3, // 当前所有能力的活跃状态总数
method: 'POST',
url: '/api/submit',
message: '请勿重复提交(第2次)'
}
}retry.scheduled
js
{
level: 'info',
event: 'retry.scheduled',
message: 'RequestGuard retry scheduled: /api/data',
data: {
capability: 'retry',
config: { /* 原始请求配置 */ },
options: { /* 当前生效的 retry 配置 */ },
error, // 本次失败捕获的错误
attempt: 2, // 当前失败的是第几次尝试(1-based)
retryIndex: 2, // 即将进入的第几次重试(1-based)
nextAttempt: 3, // 下一次尝试序号(1-based)
attempts: 3, // 配置的最大尝试次数
delay: 600, // 本次重试等待时间(ms)
status: 503, // 从错误中提取的 HTTP 状态码
code: undefined // 从错误中提取的错误码
}
}retry.exhausted
表示 retry 生命周期停止,不只是"次数用尽"。停止原因通过 data.reason 区分:
js
{
level: 'warn',
event: 'retry.exhausted',
message: 'RequestGuard retry exhausted: /api/data',
data: {
capability: 'retry',
config: { /* 原始请求配置 */ },
options: { /* 当前生效的 retry 配置 */ },
error, // 最后一次失败捕获的错误
attempt: 3, // 停止时的尝试序号(1-based)
retryIndex: 3,
attempts: 3, // 配置的最大尝试次数
reason: 'attempt-limit', // 停止原因,见下表
status: 503,
code: undefined
}
}reason 值 | 含义 |
|---|---|
attempt-limit | 达到最大尝试次数 |
non-retryable | 状态码 / 错误码不在可重试范围内,默认不可重试判断 |
circuit-open | 熔断器打开,重试被熔断拦截 |
hard-stop | clearState() / uninstall() 等主动终止 |
policy-denied | canRetry 显式返回 false 或非 true |
retry 不触发 notify
retry 的所有事件只走 logger,不触发 notify。retry 停止后返回原始错误给业务,由业务的错误处理决定是否提示用户。
circuitBreaker.blocked
js
{
level: 'warn',
event: 'circuitBreaker.blocked',
message: 'RequestGuard circuit breaker blocked: POST:/api/payment/create',
data: {
capability: 'circuitBreaker',
circuitKey: 'POST:/api/payment/create',
state: 'CIRCUIT_BREAKER',
failCount: 5,
openedAt: 1717315200000,
config: { /* 原始请求配置 */ }
}
}circuitBreaker.stateChange
js
{
level: 'warn',
event: 'circuitBreaker.stateChange',
message: 'RequestGuard circuit breaker state changed: POST:/api/payment/create NORMAL → CIRCUIT_BREAKER',
data: {
capability: 'circuitBreaker',
circuitKey: 'POST:/api/payment/create',
fromState: 'NORMAL',
toState: 'CIRCUIT_BREAKER',
failCount: 5,
openedAt: 1717315200000
}
}circuitBreaker.halfOpenProbe
js
{
level: 'info',
event: 'circuitBreaker.halfOpenProbe',
message: 'RequestGuard circuit breaker half-open probe: POST:/api/payment/create',
data: {
capability: 'circuitBreaker',
circuitKey: 'POST:/api/payment/create',
probePassCount: 0, // 当前已放行的试探请求数
probeCount: 1 // 配置的试探请求数上限
}
}circuitBreaker.recovered
js
{
level: 'info',
event: 'circuitBreaker.recovered',
message: 'RequestGuard circuit breaker recovered: POST:/api/payment/create',
data: {
capability: 'circuitBreaker',
circuitKey: 'POST:/api/payment/create',
previousState: 'HALF_OPEN',
newState: 'NORMAL'
}
}requestGuard.internalError
js
{
level: 'error',
event: 'requestGuard.internalError',
message: 'RequestGuard internal error: <phase>',
data: {
phase: '...', // 异常发生阶段,如 capability:install / pipeline / notify
error: Error, // 被隔离的内部异常
capability: '...' // 涉及的能力(可选)
}
}守护层自身异常被隔离后,请求会直接穿透到真实网络出口(见 系统特性 - 智能降级)。这个事件用于排查守护层自身的 bug,生产环境只走 logger、不裸打 console。
🔔 Notify 触发目录
notify 是统一的 UI 提示出口。guard 主动触发的用户提示都走这里,内部已隔离其异常(提示失败不影响请求结果)。真实网络错误、业务错误码不通用进入 notify——那些由业务的错误处理负责。
| 触发时机 | capability | 触发条件 | 说明 |
|---|---|---|---|
| duplicate 命中 | duplicate | showToast: true 且命中重复 | ignore 静默挂起 / block 拒绝 / reuse 等待均触发 |
| 熔断拦截 | circuitBreaker | 熔断打开,请求被拒绝 | 请求未发出 |
| 熔断状态变更 | circuitBreaker | 状态在 NORMAL/CIRCUIT_BREAKER/HALF_OPEN 间切换 | 让业务感知保护状态变化 |
| retry | — | — | 默认不触发 notify,仅走 logger |
duplicate 命中时的 payload
| 字段 | 类型 | 描述 |
|---|---|---|
| message | string | 提示文案(含重复次数,如"请勿重复提交(第2次)") |
| strategy | string | 触发策略(ignore / block / reuse) |
| capability | string | 'duplicate' |
| config | object | 原始请求配置 |
| requestKey | string | 请求唯一标识 |
| repeatCount | number | 重复次数 |
| pendingCount | number | 当前所有能力的活跃状态总数 |
| method | string | 请求方法 |
| url | string | 请求地址 |
熔断拦截时的 payload
| 字段 | 类型 | 描述 |
|---|---|---|
| message | string | 提示文案(如"请求已被熔断拦截: POST:/api/payment") |
| capability | string | 'circuitBreaker' |
| circuitKey | string | 熔断单元标识 |
| state | string | 当前熔断状态(CIRCUIT_BREAKER) |
| failCount | number | 失败次数 |
| openedAt | number | 熔断开始时间戳 |
熔断状态变更时的 payload
| 字段 | 类型 | 描述 |
|---|---|---|
| message | string | 提示文案(如"熔断状态变更: POST:/api/payment 熔断 → 半开") |
| capability | string | 'circuitBreaker' |
| circuitKey | string | 熔断单元标识 |
| fromState | string | 变更前状态 |
| toState | string | 变更后状态 |
| failCount | number | 失败次数 |
| openedAt | number | 熔断开始时间戳 |
🔧 接入示例
javascript
const requestManager = setupRequestGuard(axios, {
notify: (payload) => {
// 按能力分发到不同 UI 出口
if (payload.capability === 'duplicate') {
Toast.show(payload.message);
} else if (payload.capability === 'circuitBreaker') {
// 熔断拦截提示用户稍后重试,状态变更可静默或仅日志
if (payload.state === 'CIRCUIT_BREAKER') {
Toast.show({ content: payload.message, type: 'error' });
}
}
},
logger: new ConsoleRequestGuardLogger({ devOnly: true })
});自定义 logger 接入见 消息与日志系统 - 自定义 Logger。

