摘要

  • RFC 5263 用最终响应或超时把同一 Request-URI 的局部 NOTIFY 串行化;它证明发送窗口可以推进,不等于观察者已经形成可持久依赖的新状态。
  • 可追责的回执应把订阅、版本和消息正文绑定到 SIP 响应、解析与补丁结果、前后状态哈希、存储确认、下游可见性以及后续真人或服务结果。

超时放行了下一步,却没有观察到接收方状态

上一条 NOTIFY 没有及时返回最终响应。代理等到事务超时,按照规则结束等待,并进入相应的失败处理。此时协议已经有了一个明确事件:响应窗口耗尽。

但超时不能回答观察者究竟发生了什么。消息可能没有到达,也可能已经到达而响应丢失;观察者可能写入了新状态,也可能在解析前崩溃。发送方只看见同一个超时,接收方却可能处于完全不同的状态。

这揭示了最终响应规则的真正用途:控制发送节奏和事务生命期。无论是收到 200 还是等到超时,都不能替代接收端状态回执。

最终响应是一道发送闸门

RFC 5263 规定,同一 Request-URI 的前一条局部 NOTIFY 在获得最终响应或超时之前,在线状态代理不得发送新的局部通知。这样可以避免依赖前态的多个差异同时在路上失去顺序边界。

通用 SIP 事件规范规定,订阅方认为 NOTIFY 可接受时通常应返回 200。事务不应超过自动处理所需时间,而且不得为了等待用户反应而延迟最终响应。

所以这道闸门天生不是已读回执,也不是业务承诺。它告诉发送方何时可以离开当前事务,却不保证后面的本地应用链已经走完。

版本号必须和订阅一起解释

允许局部通知的观察者在 SUBSCRIBE 中同时声明 application/pidf-diff+xml 与 application/pidf+xml。它可以表达偏好,但代理仍可能根据本地策略选择格式。

局部格式下第一条包含在线状态的通知必须是完整文档,订阅内版本从一开始。刷新订阅不会让计数器归零;终止订阅才会。

因此,单独保存“版本 18 收到 200”远远不够。必须知道它属于哪个 Request-URI、Call-ID、对话、事件和正文哈希,才能说明发送方要求接收端从哪一个状态走向哪一个状态。

“发送成功”仍是发送方的事实

代理以此前成功发送给同一观察者、同一订阅的局部在线状态文档为基准递增版本,并在最终响应或超时后推进。

这能建立清楚的发送方记录:正文离开、事务结束、下一版本获准进入。它看不到 XML 是否解析成功、差异是否命中正确基线、结果是否落盘、重启后是否仍存在,也看不到另一个组件读到的究竟是哪一个哈希。

在平稳运行时,这些步骤常常连续完成。但相邻不等于同一。越是要用它授权告警、访问或人员调度,越不能让上游日志替下游状态作证。

接收端有三种版本分支

观察者把收到的版本与本地计数比较。等于或低于本地值时,它把文档视为代理故障并应丢弃;正好高一时,它应用差异并递增;高出超过一时,它假定有 NOTIFY 丢失,应刷新以获取完整状态或结束订阅。

三条分支对本地状态的影响完全不同。丢弃会保留旧状态;应用只有在补丁真正成功后才生成新状态;刷新意味着局部历史已经不足以继续。

发送方看到的最终响应不能替接收方记录这次比较。回执必须包含预期版本、实际版本和采取的分支。

处理错误可能不会向通知端显现

如果局部文档处理失败,RFC 5263 建议观察者续订,并允许它在新 SUBSCRIBE 中不再声明局部格式,回退到普通完整在线状态。规范还指出,即使错误存在于通知端的处理过程,把这类错误通知给它也很难称为合理。

这意味着上游可能拥有一串整齐的最终响应,而下游已经放弃差异链,等待新的完整文档。事务历史没有撒谎,只是没有覆盖本地恢复。

组织若只收集代理侧指标,就会把“没有收到错误”误读成“没有发生错误”。

格式切换会清空内容但留下计数器

当代理在同一订阅中改变通知内容类型时,观察者必须丢弃此前收到的在线状态信息,但保留本地版本计数器。这样以后切回局部格式时,计数仍可继续增长。

由此出现一种容易误判的连续性:坐标还在,坐标所指向的本地表示已经换过。只保留版本与 200 序列,无法说明哪些内容被清空、哪个完整文档成为新基线,也无法说明下游是否见过切换前的状态。

刷新时收到完整文档可以重新锚定当前状态,却不能补写已经缺失的应用历史。

消息可信不等于本地提交

RFC 5263 继承 SIP 在线状态体系关于机密性、完整性、真实性、防重放与拒绝服务的要求。它在当时的背景下建议逐跳 TLS,也允许使用 S/MIME;RFC 8996 后来以弃用 TLS 1.0 和 1.1 的方式更新了相关依赖。

伪造的局部通知可能制造版本断档,迫使观察者请求完整状态。防住这种注入十分重要。不过,即使消息来源可信、传输完整,解析、补丁、存储或展示仍可能失败。

密码学证据和 SIP 响应都应进入证据链,但两者都不能冒充本地持久化确认。

观察者状态回执

对有后果的用途,应保存:

  • 在线主体、观察者、Request-URI、订阅、对话与事件包身份;
  • 接受的内容类型、偏好与代理的本地选择;
  • NOTIFY 的 Call-ID、标签、CSeq、正文、类型、哈希和接收时间;
  • 订阅内版本与预期前一版本;
  • 最终 SIP 响应码、响应时间、超时或重试结果;
  • 解析结果与具体处理错误;
  • 应用前完整文档哈希与补丁结果;
  • 重建后文档哈希、本地计数器与存储确认;
  • 刷新、回退、格式切换和替代完整状态;
  • 下游暴露对象、哈希与观测时间;以及
  • 后续界面展示、联系尝试、交付和真人或服务结果。

这份回执不会否定 200 的价值。它只是防止事务层替自己看不见的层级作证。

Sources