← 博客
10 分钟阅读
|
发布于
|
更新于

加密支付 Webhook:工作原理与构建方法

本文说明加密支付 Webhook 如何检测充值、如何校验签名、如何处理重试与重复事件,并介绍上线前如何测试接收端点、监控失败通知,同时说明为何轮询只应作为低频的兜底手段,以及在 Chaingateway 中的具体设置步骤。

章节
C
Chaingateway Team
区块链专家

审核: Maurice Sobiera

围绕付款模块的等距 Webhook 事件流示意图

加密支付 Webhook 是区块链服务在链上发生某事时向您的服务器发送的 HTTP 请求,例如客户地址收到一笔充值。您无需每隔几秒询问网络是否有付款到账,只需向服务商提供一个 URL,由服务商回调您。

要在生产环境中运行,您需要四样东西:一个公开的端点、签名校验、对重复事件的幂等处理,以及针对漏送投递的备用机制。本指南逐一介绍这些内容。

要点速览

  • 当付款或钱包事件发生时,Webhook 会向您的服务器推送事件,您因此无需持续轮询,也就减少了对系统造成的负载。
  • 在信任请求中的任何字段之前,先校验其签名。使用 Chaingateway 时,签名只覆盖交易 ID,因此金额和收款方需要您自行核对。
  • 尽快返回 2xx 响应,然后在后台任务中完成实际工作。
  • 假定每个事件都可能重复送达:保存事件 ID,并让订单更新具备幂等性。
  • 为待处理付款保留一个低频的对账任务。Chaingateway 不会自动重试失败的通知,否则一次漏送就会让订单卡住。

什么是加密支付 Webhook?

Webhook 就是回调。您注册一个 URL,并告诉服务商您关心哪些事件。事件发生时,服务商会发送一个 POST 请求,其 JSON 正文描述该事件。对于加密支付,这些事件通常是转入受监控地址的转账、转出转账,或合约上的代币转账。

四类加密支付 Webhook 事件

另一种方式是轮询。您的服务器按计时器调用 API,并将结果与上一次看到的内容进行比较。轮询编写简单,但运行起来十分浪费。每个返回空结果的请求都会消耗速率限制、计算资源和延迟,而付款与您做出反应之间的延迟,就等于您设定的时间间隔。在多条链和成千上万个客户地址的情况下,请求数量会迅速成倍增长。

Webhook 则反转了方向。服务商监控链上数据,将交易与您订阅的地址进行匹配,并只通知您一次。反应时间缩短到几秒,而您自己的基础设施在有事情需要处理之前保持空闲。我们在如何自动处理充值的 Webhook 文章中对这一论点有更详细的阐述。

Webhook 与轮询一览

比较项轮询Webhook
由谁发起交换您的服务器服务商
反应时间与您的时间间隔一样慢接近实时
浪费的请求大部分请求没有
成本随以下因素增长地址数量乘以频率实际事件的数量
故障模式发现过晚漏送或重复送达
最佳用途对账与安全兜底主要信号

最后一行给出了实际的答案。Webhook 应作为主要信号,而轮询应作为低频的兜底,只检查仍处于待处理状态的付款。轮询只针对仍待付款的账单进行检查,这样漏送的投递可以在几分钟内被发现,请求数量也保持在较低水平。

Webhook 如何检测加密支付?

服务商一侧是您看不到的部分,但理解它有助于解释您在测试中遇到的大部分行为。

  1. 订阅。您创建钱包或注册地址,然后通过服务商的 API 为其注册 Webhook。该订阅包含您的回调 URL,以及发送方、接收方、合约地址和交易类型等过滤条件。
  2. 监控。服务商为每条受支持的链运行节点,并读取每一个新区块。每笔交易都会与订阅进行匹配;对于代币,则与合约转账日志进行匹配。
  3. 解码。原始链上数据并不便于使用。以太坊上的代币转账是一条经过编码的日志条目,而比特币使用的是输入与输出,而非发送方与接收方。服务商会将其转换为可读的负载。
  4. 投递。服务商将负载发送到您的 URL。如果您的服务器未能返回成功状态码,接下来会发生什么取决于服务商。有些服务商会按计划重试。Chaingateway 不会自动重试:它会列出失败的通知,由您逐一请求重新发送。

Chaingateway 的通知包含以下字段:id、webhook_id、from、to、blocknumber、datetime、type、contractaddress、tokenid、txid 和 amount。以太坊、BNB Smart Chain、Polygon、Arbitrum 和 Tron 使用相同的字段名称。比特币 Webhook 仅按发送方和接收方过滤。Solana 不提供 Webhook。支持 ERC-20、BEP-20 和 TRC-20 等代币标准,这一点很重要,因为现实中的大多数付款是稳定币转账,而非原生币。

值得订阅的事件

先从窄范围开始。在 Chaingateway 中,Webhook 由过滤条件定义,因此每种事件类型都对应一组过滤条件组合:

  • 转入客户充值地址的转账使用 to。这是为账户入账或将账单标记为已付款的核心事件。
  • 转出转账使用 from,例如用于查看付款或归集何时上链。
  • 代币转账使用 type(如 ERC20 或 TRC20)加上 contractaddress。
  • NFT 转账使用 token_id 字段,并搭配 ERC721 或 TRC721 类型。
  • 可选的 reference 字段最多可包含 255 个字符,让您能够将 Webhook 与自己系统中的订单或客户关联。

通知表示已看到符合过滤条件的交易。您是否将其视为最终到账,由您自己的策略决定,确认深度一节对此有所说明。

我们关于无需轮询的 Polygon Webhook的文章展示了单条链上的具体做法。

如何设置并处理 Webhook 接收端点?

接收端点就是您服务器上的一条普通 HTTPS 路由。演示与生产环境处理程序之间的区别,主要体现在几个习惯上。

端点要求

该 URL 必须能通过 HTTPS 从公共互联网访问。本地地址和私有网络无法接收调用,因此在开发阶段,您需要一个能暴露本地端口的隧道。该路由应专用于 Webhook,只接受 POST 请求,并且不要将其置于会拒绝来自机器请求的登录页面或 CSRF 中间件之后。

处理程序应快速响应。常见的做法,例如 Stripe 的 Webhook 文档所建议的,是在任何可能超时的复杂逻辑之前,尽快返回成功的状态码。这里的成功指 RFC 9110 定义的 2xx 状态码。加密事件同样适用这一规则。如果您在响应之前需要更新数据库、发送邮件并调用会计系统,那么某个缓慢的下游服务就可能让服务商将本次投递视为失败。

一种可靠的模式如下:

  1. 读取请求正文。
  2. 校验签名。
  3. 将事件及其 ID 写入队列或事件表。
  4. 返回 200。
  5. 由工作进程处理排队中的事件。

如何校验 Webhook 签名?

任何找到您 URL 的人都可以向其发送 JSON。如果您的处理程序因为某个请求声称有充值到账而为账户入账,那么伪造的请求就等同于盗窃。签名校验可以关闭这扇门。

典型方案是 HMAC,由 RFC 2104 定义。服务商使用一个只有您和它知道的密钥计算哈希值,并将结果放在请求头中发送。您重新计算哈希并进行比对。有三个细节容易出错:

  • 明确签名的内容。许多服务商对整个请求正文进行签名,这意味着您必须对原始字节进行校验,而不是对重新序列化的 JSON 进行校验。Chaingateway 只对交易 ID 签名。
  • 以恒定时间比对。使用您所用语言的安全比较函数,而不是普通的相等判断。
  • 如果方案提供了时间戳,就检查它。拒绝过旧的时间戳可以限制被截获请求的重放。Chaingateway 的方案没有时间戳,因此应以交易 ID 进行去重。

在您的个人资料中设置个人密钥后,Chaingateway 会在 X-Signature 请求头中发送签名。其值是以该密钥对 txid 字段计算的 HMAC-SHA256 再经 Base64 编码的结果。签名校验指南提供了可运行的 Node.js 处理程序,文档则提供了 Python、Java 和 PHP 版本。由于只对 txid 签名,有效的签名并不能证明 amount 或 to 未被更改。在入账之前,请将它们与您的账单或链上数据进行核对。

请将密钥保存在环境变量或密钥管理器中,切勿放入代码仓库;如果它曾出现在日志中,请重新生成。重新生成的密钥会立即生效。

如何处理重试、重复和缓慢的确认?

网络会出故障,部署也会重启服务器。您的处理程序最终一定会两次收到同一个事件,例如在重新发送之后,有时事件还会乱序到达。从一开始就应为此进行设计。

让处理具备幂等性

每个事件都带有能够标识它的信息。在 Chaingateway 的通知中,这就是 txid 连同 webhook_id。在采取行动之前,先用唯一约束保存这一标识。如果由于该键已存在而插入失败,说明您已经处理过该事件,可以直接返回 200,无需执行任何操作。

然后让业务操作本身可以安全地重复执行。“将账单 1042 标记为已付款,交易为 X”是幂等的。“将余额增加 50”则不是。优先采用前一种形式,或者将余额变动与唯一的事件记录放在同一个数据库事务中。

幂等事件处理的正确与错误做法:以唯一约束保存标识,插入失败时返回 200,将账单标记为已付款并附带交易,不要直接增加余额

尊重确认深度

交易出现在区块中,并不等同于可以据此发货的付款。不同的链在区块变得不太可能被回滚的速度上有所不同,合适的阈值取决于金额和资产。请按链和订单规模制定策略,并保存每笔付款的状态:已检测、确认中、已确认、失败。宣告检测到付款的 Webhook 应将订单推进到“已看到付款”,而不是“已履约”。

少付、多付与错误代币

客户发送错误金额的情况比人们预期的更为常见。您的处理程序应将收到的金额和资产与账单进行比较,并分别处理:完全一致、少付、多付,或出现意外代币。应事先决定是否自动入账差额、转入人工复核,还是退款。将资产和金额作为独立字段的解码负载,可以把这种比较简化为几行代码,而不是一项解析工作。

保留安全网

投递可能失败,而 Chaingateway 不会重试。失败的通知会出现在 GET /api/v2/<chain>/webhooks/notifications/failed 中,您可以使用 POST /api/v2/<chain>/webhooks/notifications/{id}/retry 逐一重新发送。每隔几分钟运行一次定时任务,检查该列表,并查看超过合理时间仍处于待处理状态的账单。当它发现 Webhook 从未报告的付款时,将其送入相同的处理路径。两种来源共用一条代码路径,也就只需维护一套缺陷。

如何测试与监控 Webhook 接收端点?

分层建立信心:

  1. 本地测试。编写一个小脚本,使用测试密钥对示例负载签名,并将其发送到您的端点。确认有效签名能够通过,而修改过的 txid 会失败。
  2. 测试网运行。使用请求头 X-Network: testnet 在测试网上创建钱包,注册 Webhook,并从水龙头发送一笔小额转账。您将看到真实的事件顺序,包括通知出现前的延迟,这是任何示例负载都无法体现的。
  3. 重复演练。将同一个有效事件发送五次。您的账单应只改变一次,日志中则应显示四次被跳过的重复事件。
  4. 故障演练。故意让处理程序返回 500。然后在失败列表中找到该通知,恢复处理程序并重新发送。它应只被处理一次。

上线后,记录每个收到的事件 ID、校验结果、处理结果以及耗时。针对三类情况设置告警:签名失败(密钥配置错误或存在攻击者)、队列不断增长(工作进程落后),以及账单待处理时间远超正常水平(无声的投递问题)。

常见问题及其通常原因:

症状可能原因
签名始终不匹配密钥错误或已重新生成,或哈希计算的内容有误(应为 txid,而非整个正文)
没有收到任何事件URL 无法公网访问、防火墙拦截、地址未订阅、网络选择错误
同一事件被处理两次事件 ID 上没有唯一约束
通知出现在失败列表中处理程序响应缓慢,或返回了非 2xx 状态码
付款入账过早业务逻辑基于检测结果而非确认结果执行

如何在 Chaingateway 中开始接收付款事件?

只需一个请求即可创建 Webhook:POST /api/v2/<chain>/webhooks。下面的示例注册了一个 TRC20 充值监听器,并附带您的订单引用:

Terminal window
curl -X POST https://app.chaingateway.io/api/v2/tron/webhooks \
-H "Authorization: Bearer $CHAINGATEWAY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"to": "TWrTTVizHkF3LxTiWE9vCnhWC7CBpNXe22",
"contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"type": "TRC20",
"url": "https://shop.example.com/hooks/crypto",
"reference": "order-10442"
}'

Chaingateway Webhooks 与 Blockchain API 协同工作,因此告知您充值已到账的事件,与将其继续转发的调用,都位于同一个账户之下。

Chaingateway 首页截图:面向加密支付与 Webhook 的统一区块链 API,覆盖 7 条链

套餐价格公布在价格页面上:Plus 每月 €49,Pro 每月 €99,Premium 每月 €249,Enterprise 每月 €499;按年计费时分别为每年 €490、€990、€2,490 和 €4,990。7 天免费试用无需银行卡,也无需 KYC,因此您可以先接好端点,再进行上述演练。

常见问题

使用 Webhook 后还需要轮询吗?

需要,但只需少量轮询。以 Webhook 作为主要信号,并定期检查仍待付款的订单,避免从未送达的投递让订单卡住。该检查发现的任何付款,都应通过与 Webhook 事件相同的处理代码进行处理。

如何确认 Webhook 确实来自服务商?

使用共享密钥校验签名请求头,并拒绝未通过校验的请求。对于 Chaingateway,即校验 X-Signature 请求头,即对 txid 计算的 HMAC,以及您在个人资料中设置的个人密钥。即使 URL 是保密的,也绝不要信任未签名请求的内容。

我的端点应返回什么?

在完成校验并保存事件后,立即返回 2xx 状态码。将邮件、账本更新和第三方调用等耗时操作放到后台工作进程中处理。响应缓慢或失败会使通知进入失败列表,之后重新发送时会再次投递。

一套 Webhook 配置能否覆盖多条区块链?

如果服务商对数据进行了标准化,就可以。Chaingateway 在以太坊、BNB Smart Chain、Polygon、Arbitrum 和 Tron 上使用相同的通知字段,因此一个处理程序即可处理来自所有这些链的事件,并在您自己的逻辑中设置各链的确认规则。比特币 Webhook 仅按发送方和接收方过滤,而 Solana 不提供 Webhook。

资料来源

推荐阅读

我们如何撰写这些文章

准备好自己动手构建了吗? 获取你的 API key — 7 天试用,无需信用卡 — 或查看 区块链 API 获取完整的 endpoint 参考。

C
Chaingateway Team
区块链专家

Chaingateway 团队致力于为全球开发者简化区块链集成。