网络钩子困境待解:SCROLL 协议能否带来新转机?
网络钩子Webhooks的困境2026 年 8 月 5 日机器之心编辑部为您带来网络钩子相关困境的深度解析。如今在三家不同公司为三个不同供应商搭建同一系统时虽该系统无正式名称且未出现在路线图上但每次情况相似即客户的真实数据存于他人数据库如用户信息在身份验证提供商处订阅信息在 Stripe 里退信信息在负责发送邮件的平台而产品需在本地保存这些数据于是订阅网络钩子webhooks并保留副本。第一次搭建时原以为只是构建一个端点编写一条路由解析 JSON 数据并更新数据库中的一行记录一下午就能完成。然而实际工作从一下午变成了一周。首先要进行签名验证因为可修改数据库的开放端点如同安全漏洞接着需设置去重表因消息可能重复推送文档称其为“至少推送一次”处理程序需要缓冲区因为 membership.created 事件有时会在其所依赖的 user.created 事件之前出现之后要有初始数据导入程序由于网络钩子只告知订阅之后发生的事情且与实时事件存在竞争问题所以需要锁机制最后是数据对账定时任务该任务会在凌晨 3 点爬取供应商的列表 API将数据与表进行比对并悄悄修复不一致之处。这个定时任务本质像是一份书面忏悔表明不信任自己构建的数据副本也不知其何时出错所以每晚从头重新推导数据。信任缺失是有原因的数据偏差不会主动暴露我们是通过一张客户支持工单发现问题的如客户几个月前取消订阅但数据库仍显示“活跃”状态某些 customer.subscription.deleted 事件在传输过程中丢失且无地方能察觉该问题他们的仪表盘显示消息已重试但最终被丢弃而我们的日志也无法记录从未到达的请求。这还只是代码层面的问题每个供应商都有自己的仪表盘三个供应商就有三个网络钩子配置页面每个页面对于端点注册方式、事件类型、测试和生产环境的区分方式以及签名密钥的存储位置都有不同规定。出现问题时调试就像一场旅行需在不同标签页查看推送日志、我们的日志以及怀疑有问题的仪表盘。到第三次搭建这个系统时不再抱有幻想提前为整个技术栈签名验证、去重、缓冲、数据导入、定时任务做好预算。当写到第三个去重表时终于问出了第一次搭建时就该问的问题我到底在重建什么通知并非数据实际上是在重建一个有序的日志每次集成都是试图将一系列通知重新转化为它们原本所属的有序、完整、最新的历史记录。荒谬的是这个历史记录存在于供应商的系统里供应商依据它来渲染仪表盘、事件页面和网络钩子重放工具。供应商将有序的日志拆分成一个个 HTTP POST 请求通过既不能保证顺序也不能保证送达的通道发送到端点然后再在自己这边重新组装日志其他每个消费者也都在独立地做这件事且各自都有问题。这就像一个拼图游戏制造商有原图把它剪成碎片一片一片地寄给我们途中还丢了几片有些还寄了两次而且盒子上没有任何图案。当拼好的拼图和原图不一样时他们的客服却问少了哪些碎片而我们根本不知道关键在于没有任何迹象表明有缺失。这并非任何供应商的问题他们的网络钩子完全按照文档工作。问题在于网络钩子的本质它是一种通知“某事发生了这是一个相关的 POST 请求”。通知是触发副作用的好方式但却是传输数据集的糟糕方式。不知从何时起我们开始用它来做传输数据集这件事却没意识到任务已经变了。为何这成了常态这并非有人刻意决定的。“网络钩子”这个术语是 Jeff Lindsay 在 2007 年创造的早期应用很合适如 GitHub 的提交后钩子触发 CI 构建或者支付事件通知服务器发送收据。当时的任务是在某事发生时执行另一件事对于这种情况POST 请求非常完美在可以接受丢失的情况下“即发即忘”的方式没问题。网络钩子之所以流行是因为它对供应商来说是成本最低的交付方式只需一个 HTTP POST 请求对消费者来说也是成本最低的接收方式已有一个 Web 服务器只需添加一条路由。到 2010 年代初“我们支持网络钩子”成了每个 API 主页上的必选功能但这个选项从未区分过两种截然不同的任务一是触发副作用如发送收据、启动构建、通知频道二是确保本地保存的供应商数据准确无误如客户删除了支付方式那么也在数据库中更新该信息。第一项任务是网络钩子诞生的初衷而三次搭建系统做的都是第二项任务恰恰在这项任务中网络钩子所缺乏的所有特性顺序性、完整性、初始数据同步、可验证性都是我们所需要的。我们在 2007 年选择了现成的工具然后花了十五年时间来弥补它的不足。困境进化生物学中有一个概念“适应度景观”山峰代表好的设计山谷代表糟糕的设计生物种群会朝着所处位置的上坡方向进化。陷阱在于“局部最优”一个小山丘比周围的环境好于是进化就停留在了这里即便山谷对面有更高的山峰。要到达更高的山峰意味着要经历暂时更差的设计而进化不会选择暂时变差的路径。用网络钩子进行数据复制就是一个局部最优解证据就是山谷底部堆积如山的解决方案如签名方案、去重存储、幂等处理程序、供应商端带有指数退避策略的重试队列以及其后的死信队列、带有重放工具的网络钩子日志因为消费者不断要求重放还有凌晨 3 点运行的定时任务。在这堆解决方案之上还形成了一个产业。Svix 的出现让供应商无需自行构建网络钩子推送系统Hookdeck 的存在让消费者无需自行构建网络钩子接收系统。AWS 会将这个“山谷”打包成托管服务卖给我们用 EventBridge 接收 SaaS 合作伙伴的事件用 SQS 对事件进行排队用 Lambda 重试处理程序而我们需要自己组装整个流程。整个连接器平台行业Fivetran、Airbyte 以及每个“统一 API”初创公司本质上都是伪 CDCChange Data Capture变更数据捕获通过网络钩子和轮询列表 API 重建数据变更捕获一次构建一个定制连接器然后作为产品出售。在数据库内部捕获变更已经是一个解决了的问题那就是复制而它之所以有效是因为有日志。但在不同公司之间我们却用门铃式的网络钩子来重建这个功能。最喜欢的解决方案是本地隧道很多供应商都提供类似 stripe listen 的 CLI 工具用于在笔记本电脑上打开一个隧道因为网络钩子无法访问本地主机。当多个供应商都需要提供本地隧道以便开发者进行开发时说明这个基础工具的设计方向是错误的。这些工具本身并不是糟糕的工程设计相反它们是优秀的工程成果。这就是局部最优的样子大量优秀的工程投入到山谷底部让山谷变得舒适以至于没有人再抬头看。但有些供应商已经开始抬头了。Stripe 保留了 [30 天的事件记录](https://docs.stripe.com/api/events)并提供了 [/v1/events](https://docs.stripe.com/api/events/list) 接口这是一个有序的、可列出的日志并且 [建议根据它进行数据对账](https://docs.stripe.com/webhooks/process-undelivered-events)。WorkOS 推出了 [Events API](https://workos.com/docs/events/data-syncing/events-api)这是一个有序的、可分页的日志并且 [他们自己的文档建议在数据一致性很重要时使用该 API 而非网络钩子](https://workos.com/docs/events/data-syncing)。日志不断地以各种形式出现每次出现都有自己独特的游标语义、初始数据同步方式没有验证副本的方法也没有统一的规范但方向是明确的这就是趋同进化。日志无处不在但缺乏统一的规范。能否做得更好在考虑新的设计之前值得思考一下任何替代方案实际上需要具备哪些特性。三次集成的经历表明需要具备以下几点顺序性这样变更就可以无需缓冲直接应用能够从零开始同步这样初始数据导入就不会与实时事件产生竞争将删除操作视为数据这样数据缺失就不再是错误模式可恢复性这样系统停机就是自己的问题而不是数据丢失事件以及某种验证结果的方法这样就不用依赖凌晨 3 点的定时任务来维持信任。按照这个标准来衡量现有的明显候选方案都有所欠缺。更频繁地轮询列表 API 其实就是将数据对账定时任务提升为一种整体策略它可以重建当前状态但会消耗大量的速率限制来发现大部分数据并没有变化它无法保证顺序性而且已删除的对象和从未存在过的对象看起来没有区别。托管推送服务无论是供应商端的 Svix还是这边的 EventBridge 和 SQS都能让推送更加可靠但它们仍然是推送仍然没有初始数据同步仍然无法验证仍然是用通知来假装成数据集。这条路只是加固了山谷底部而没有朝着更高的山峰前进。第三个候选方案是供应商一直在部分实现的完全停止推送让消费者自己读取日志。反转数据流那么做个思想实验如果不是让供应商在有新信息时通知我们而是我们主动询问供应商自上次检查后有哪些新信息会怎么样呢假设供应商为每个数据集提供一个 URL该 URL 返回一个有序的、通过游标寻址的完整状态事件变更日志。不携带游标进行请求将从日志开头开始读取这就是初始数据同步无需单独的导入操作也不会有竞争问题。携带游标进行请求将从上次中断的地方继续读取整个同步状态就由这个游标来表示。发送 Prefer: stream 头响应将不会结束每一个变更在提交时就会通过打开的连接发送过来使用的是用于正常 REST 端点的相同 API 密钥。不发送该头将得到一个有边界的页面可以通过定时任务进行轮询。这是同一个端点、相同的事件、相同的游标和相同的消费者代码。这并非什么新奇的东西只是一个分页的 GET 请求。但回顾一下原本一下午就能完成却越做越复杂的工作看看这个方案对整个技术栈有什么影响去重表不再需要每个事件都包含对象的完整当前状态因此应用一个事件就是根据 ID 进行盲目更新操作同一个事件应用两次会产生相同的结果排序缓冲区不再需要因为日志是有序的初始数据导入程序及其锁机制不再需要新的消费者可以不带游标读取同一个日志流重放数据集并在一个请求中直接处理实时变更丢失删除操作不可能发生删除标记是日志中的一个事件它会一直存在直到被读取已取消订阅的客户不会再无声无息地显示为“活跃”状态因为数据缺失不再是错误模式端点、签名验证和本地隧道从一开始就不需要所有连接都是由消费者发起的整个同步过程可以在 NAT 之后、笔记本电脑上或定时任务中运行。日志流还可以携带另外一项信息。当读取到达日志末尾时供应商可以告知当前应该有的数据状态在持有的游标位置处的记录数量和校验和。将两者进行比较就能确定副本是正确的而不是靠猜测。凌晨 3 点运行的定时任务那份书面忏悔将变成一个在原本打算安排定时任务之前就已经完成的比较操作。第四次搭建如果存在这样一个日志流那么第四次搭建这个系统时只需要一个循环发送 GET 请求获取日志流让“更新插入”操作将对象更新或插入到数据库中“删除”操作则删除相应对象并保存最后一个游标。这只需要二十行代码无需路由、无需轮换密钥、无需队列也无需定时任务。副本本身就带有正确性证明当有人询问哪些客户有活跃订阅且邮箱地址有退信时答案就是在本地表上进行 JOIN 查询不会有任何隐藏的问题。目前还没有人提供这样的服务这既是挑战也是机会。SCROLL 协议为了看看这个想法在精确描述后是否仍然可行将其写成了一个协议草案**SCROLL**即 Synchronized Change Replication Over Line Logs基于行日志的同步变更复制。这是一个征求意见稿draft - 00它明确了日志流、游标、流式和轮询模式、检查点、删除标记和数据保留等方面的内容同时也标注了自己信心不足的地方。而且它不需要等待供应商的支持因为可以通过一个中间件从任何供应商现有的网络钩子和列表 API 合成日志流也打算通过这种方式找出设计中的问题。如果您也深陷过这个困境如果编写过去重表、调试过数据对账定时任务或者遇到过删除操作丢失的问题请阅读这个协议草案并反馈它在哪里存在问题。有不同意见是我们期望的反馈沉默才是失败。

相关新闻

告别C盘爆红烦恼,Windows Cleaner如何让系统重获新生?

告别C盘爆红烦恼,Windows Cleaner如何让系统重获新生?

告别C盘爆红烦恼,Windows Cleaner如何让系统重获新生? 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服! 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner 你是否曾经历过这样的场景&#xff…

2026/8/7 17:41:20 阅读更多 →
Python全栈实战:Docker Compose + Nginx 部署 FastAPI、Vue3 与 MySQL

Python全栈实战:Docker Compose + Nginx 部署 FastAPI、Vue3 与 MySQL

Python全栈实战:Docker Compose Nginx 部署 FastAPI、Vue3 与 MySQL 完成一个全栈项目的开发只是第一步,将它真正部署到生产环境并稳定运行才是更大的挑战。本文将带你从零开始,使用Docker Compose和Nginx,将FastAPI后端、Vue3前…

2026/8/7 19:16:51 阅读更多 →
学术研究的“瑞士军刀”:宏智树AI全流程科研平台深度解析

学术研究的“瑞士军刀”:宏智树AI全流程科研平台深度解析

如果你正在写论文,无论是本科毕业论文还是硕士研究,大概都经历过这样的场景:开题报告用一个模板,文献综述靠手动翻知网,数据分析打开SPSS对着教程一步步操作,查重又要切换到另一个平台——每个环节都要折腾…

2026/8/7 23:10:16 阅读更多 →

最新新闻

Python 玩转企微协议:朋友圈、标签与邀请确认等高阶接口实战

Python 玩转企微协议:朋友圈、标签与邀请确认等高阶接口实战

​​QiWe开放平台 个人名片 API驱动企微外部群自动化,让开发更高效 官方站点:https://www.qiweapi.com 对接通道:进入官方站点联系客服 团队定位:企微生态深度服务,专注 APIRPA 融合技术方案 真正的私域闭环不仅仅是群…

2026/8/8 13:08:58 阅读更多 →
APP上架全攻略:从合规自查到多平台提审避坑指南

APP上架全攻略:从合规自查到多平台提审避坑指南

1. 项目概述:为什么需要一份全面的上架指南? 每次准备把新开发的APP推向市场,最头疼的环节之一就是应对各大应用商店五花八门的审核规则。你可能遇到过这种情况:在华为应用市场审核顺利通过,到了小米应用商店却因为一个…

2026/8/8 13:08:58 阅读更多 →
Python 自动化运营:基于协议接口的企微外部群全生命周期管理

Python 自动化运营:基于协议接口的企微外部群全生命周期管理

​QiWe开放平台 个人名片 API驱动企微外部群自动化,让开发更高效 官方站点:https://www.qiweapi.com 对接通道:进入官方站点联系客服 团队定位:企微生态深度服务,专注 APIRPA 融合技术方案 外部群是私域运营的核心阵地…

2026/8/8 13:08:58 阅读更多 →
怎么把 Word 导出为纯图格式的 PDF?用不坑盒子每页转成图、排版锁死

怎么把 Word 导出为纯图格式的 PDF?用不坑盒子每页转成图、排版锁死

一份排好版的 Word 发出去,最怕两件事:一是对方电脑缺字体、Office 和 WPS 版本不一样,打开版式全乱;二是被人随手就把内容改了、把文字整段复制走。想两样一起堵住,就把它导成纯图格式的 PDF——每一页都是一张图&…

2026/8/8 13:08:58 阅读更多 →
Go 语言+RPA实现企微外部群消息自动化发送

Go 语言+RPA实现企微外部群消息自动化发送

​​QiWe开放平台 个人名片 API驱动企微自动化,让开发更高效 官方站点:https://www.qiweapi.com 对接通道:进入官方站点联系客服 团队定位:企微生态深度服务,专注 APIRPA 融合技术方案 大家好!做过企微开发…

2026/8/8 13:08:58 阅读更多 →
YOLO模型对比与LLM集成:构建鲁棒疲劳驾驶识别系统实践指南

YOLO模型对比与LLM集成:构建鲁棒疲劳驾驶识别系统实践指南

在实际的智能驾驶和工业安全监控场景中,疲劳驾驶识别是一个典型且关键的计算机视觉应用。单纯依赖单一的目标检测模型,往往难以应对复杂多变的真实环境,例如光照变化、驾驶员姿态多样、遮挡以及模型对不同疲劳特征(如闭眼、打哈欠…

2026/8/8 13:07:58 阅读更多 →

日新闻

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

AI多智能体时代来临,读懂MCP与A2A架构,抢占企业数字化新风口

当下AI应用飞速普及,无数企业下场搭建智能体系统,可落地阶段难题接踵而至:上下文无限堆积频繁爆栈、AI工具调用准确率低下、Token成本居高不下、企业数据权限混乱暗藏安全隐患……很多团队卡在架构搭建环节,空有前沿技术概念&…

2026/8/8 0:00:07 阅读更多 →
PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码

PHP二维码生成终极指南:用chillerlan/php-qrcode打造专业级二维码 【免费下载链接】php-qrcode A PHP QR Code generator and reader with a user-friendly API. 项目地址: https://gitcode.com/gh_mirrors/ph/php-qrcode 在当今数字时代,二维码已…

2026/8/8 0:00:08 阅读更多 →
UniApp微信小程序隐私保护组件开发:从原理到实战

UniApp微信小程序隐私保护组件开发:从原理到实战

1. 项目缘起:为什么我们需要一个隐私保护通用组件?最近在维护一个基于uniapp开发的微信小程序矩阵时,我遇到了一个非常棘手的问题。随着平台对用户隐私保护的要求越来越严格,几乎每一个新版本发布,或者在某些特定机型&…

2026/8/8 0:00:08 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/6 22:02:27 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/8 8:58:26 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/7 23:24:08 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/7 17:02:37 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/7 23:54:54 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/7 17:02:36 阅读更多 →