SPECIFICATION
第 9 章 错误处理
9.1 错误处理模型
DTP 实现 必须 遵循"检测-通知-恢复"三阶段错误处理模型:
- 检测:识别异常情况。
- 通知:向对端或上层发送错误信息。
- 恢复:根据错误类型采取恢复措施。
实现 不得 在检测到错误时静默丢弃帧而不通知。
9.2 错误码体系
DTP 必须 使用以下错误码体系。错误码 必须 是非负整数,按功能模块划分为八个范围:
| 范围 | 类别 | 处理策略 |
|---|---|---|
| 1xxx | 帧处理错误 | 丢弃帧 + 通知发送方 |
| 2xxx | 加密错误 | 丢弃帧 + 通知发送方 + 可能触发密钥重协商 |
| 3xxx | 约定错误 | 丢弃 Fragment + 通知发送方 + 可能触发重新协商 |
| 4xxx | DAG 错误 | 拒绝 Fragment + 通知发送方 或 缓存等待 |
| 5xxx | 会话错误 | 尝试恢复会话 + 失败时关闭并通知上层 |
| 6xxx | 续传错误 | 暂停发送 + 通知上层应用 |
| 7xxx | 版本错误 | 发送版本不兼容通知 + 尝试降级处理 |
| 8xxx | 权限错误 | 拒绝操作 + 通知请求方 |
9.3 错误码定义
实现 必须 使用以下规范化的错误码定义。不得 使用未列出的错误码。如需扩展,必须 在本规范的后续版本中定义。
9.3.1 帧处理错误(1xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 1001 | FRAME_DESERIALIZATION_FAILED | 接收到的二进制数据无法反序列化为 LogicalFrame |
| 1002 | FRAME_INVALID_FORMAT | LogicalFrame 结构无效或缺少必需字段 |
9.3.2 加密错误(2xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 2001 | DECRYPTION_FAILED | Payload 解密失败(错误密钥或数据损坏) |
| 2002 | KEY_NOT_READY | CAP 密钥交换尚未完成,拒绝数据传输 |
9.3.3 约定错误(3xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 3001 | AGREEMENT_NOT_FOUND | Fragment 引用了未知 Agreement_ID |
| 3002 | AGREEMENT_EXPIRED | 引用的约定已过期(超过 validityPeriod) |
| 3003 | AGREEMENT_NEGOTIATION_FAILED | 协商无法完成(超时、对端拒绝重协商等) |
9.3.4 DAG 错误(4xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 4001 | DAG_CYCLE_DETECTED | 添加 Fragment 会形成 DAG 环路 |
| 4002 | DAG_DEPENDENCY_UNRESOLVED | Fragment 依赖未在缓存超时内解析 |
9.3.5 会话错误(5xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 5001 | SESSION_NOT_FOUND | 引用的 Session_ID 不存在 |
| 5002 | SESSION_TIMEOUT | 会话因不活动超时 |
| 5003 | SESSION_RESTORE_FAILED | 重连后会话恢复失败 |
9.3.6 续传错误(6xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 6001 | BUFFER_FULL | 发送方未确认 Fragment 缓存达到容量上限 |
| 6002 | RETRANSMISSION_TIMEOUT | Fragment 重传超时未收到确认(重传次数耗尽) |
9.3.7 版本错误(7xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 7001 | VERSION_INCOMPATIBLE | 接收帧的协议版本号高于自身支持版本 |
9.3.8 权限错误(8xxx)
| 错误码 | 名称 | 触发条件 |
|---|---|---|
| 8001 | PERMISSION_DENIED | 当前角色不允许执行该操作 |
| 8002 | OBSERVER_WRITE_DENIED | 旁观者尝试写操作(旁观者只读) |
9.4 错误唯一性
实现 必须 保证错误码的唯一性:
- 每个错误码 必须 对应唯一的错误类型。
- 不同错误类型 不得 共享同一错误码。
- 实现 不得 重新定义本规范已分配的错误码。
9.5 错误通知机制
9.5.1 ErrorNotificationFrame
错误通知 必须 通过 ControlFrame 传递,定义如下:
interface ErrorNotificationFrame {
frameType: "control";
controlType: "error_notification";
errorCode: DTPErrorCode;
errorMessage: string;
relatedFrameId?: FragmentID;
relatedAgreementId?: AgreementID;
details?: Record<string, unknown>;
}
| 字段 | 规范性要求 |
|---|---|
frameType | 必须 为 "control" |
controlType | 必须 为 "error_notification" |
errorCode | 必须 为 9.3 节定义的错误码之一 |
errorMessage | 必须 为人类可读的错误描述。应 使用对端可理解的语言 |
relatedFrameId | 可选。当错误由特定帧触发时 必须 包含该帧的 fragmentId |
relatedAgreementId | 可选。当错误与特定约定相关时 必须 包含 Agreement_ID |
details | 可选。可 包含调试用的额外信息 |
9.5.2 错误通知传输
ErrorNotificationFrame 必须 通过常规 LogicalFrame 通道传输,必须 加密 Payload。
如错误本身导致无法加密(例如 KEY_NOT_READY 错误),实现 可 通过实现定义的带外通道返回错误,但 不得 在加密通道中以明文发送错误。
9.6 关键错误处理流程
9.6.1 反序列化失败(1001)
接收到的 LogicalFrame 无法反序列化时,接收方 必须:
- 丢弃该帧。
- 发送
FRAME_DESERIALIZATION_FAILED错误通知。 - 不得 因反序列化失败而关闭会话。
9.6.2 解密失败(2001)
接收到的 Payload 无法解密时,接收方 必须:
- 丢弃该帧。
- 发送
DECRYPTION_FAILED错误通知。 - 计数连续解密失败次数。
- 如连续失败超过阈值(推荐 3 次),应 触发 CAP 重新密钥交换。
9.6.3 DAG 环路检测(4001)
检测到 DAG 环路时:
- 接收方 必须 拒绝该 Fragment。
- 必须 返回
DAG_CYCLE_DETECTED错误。 - 不得 将 Fragment 加入 DAG。
- 不得 影响已存在 Fragment 的状态。
9.6.4 未知约定(3001)
Fragment 引用了未知 Agreement_ID 时:
- 接收方 必须 丢弃 Fragment。
- 返回
AGREEMENT_NOT_FOUND错误。 - 可 触发重新协商(实现定义)。
9.6.5 密钥未就绪(2002)
CAP 密钥交换尚未完成时尝试发送数据:
- DTP_Engine 必须 拒绝发送。
- 必须 返回
KEY_NOT_READY错误给上层调用方。 - 不得 在通信通道中以明文形式响应。
9.6.6 缓存已满(6001)
未确认 Fragment 缓存达到上限时:
- 发送方 必须 暂停发送新 Fragment。
- 发送
BUFFER_FULL通知给上层应用。 - 在确认释放缓存空间后恢复发送。
- 不得 丢弃已缓存的 Fragment。
9.6.7 重传超时(6002)
Fragment 重传次数耗尽时:
- 发送方 必须 通知上层应用
RETRANSMISSION_TIMEOUT错误。 - 应 触发会话挂起或终止。
- 不得 无限重传。
9.6.8 版本不兼容(7001)
接收到协议版本不兼容的帧时(详见第 10 章):
- 接收方 必须 不处理该帧。
- 必须 返回
VERSION_INCOMPATIBLE错误。 - 必须 在错误的
details字段中包含自身支持的最高版本号。
9.6.9 权限拒绝(8001、8002)
非法的角色操作时:
- DTP_Engine 必须 拒绝该操作。
- 旁观者写操作 必须 返回
OBSERVER_WRITE_DENIED(8002)。 - 其他权限拒绝 必须 返回
PERMISSION_DENIED(8001)。
9.7 错误恢复策略
实现 必须 按错误类型采取相应恢复策略:
| 错误类别 | 恢复策略 |
|---|---|
| 1xxx 帧处理 | 丢弃帧,记录日志,继续接收后续帧 |
| 2xxx 加密 | 单次失败丢弃帧,连续失败触发密钥重协商 |
| 3xxx 约定 | 丢弃 Fragment,可能触发重新协商 |
| 4xxx DAG | 环路:拒绝;未解析:缓存等待 |
| 5xxx 会话 | 尝试恢复会话;失败则关闭 |
| 6xxx 续传 | 暂停发送,等待对端响应或上层介入 |
| 7xxx 版本 | 发送版本通知;尝试降级处理 |
| 8xxx 权限 | 拒绝操作,不得 自动重试 |
实现 不得 在权限错误(8xxx)发生时自动重试相同操作。
