你运行 ngrok http 3000。复制 URL。粘贴到 Stripe 控制台。调试一个小时,合上笔记本,第二天早上又得把整套流程重来一遍,因为那个 URL 已经没了。
这不是什么难题。它是一道每天都会重新裂开的小口子,而大多数答案不是“花钱买个固定域名”,就是“换个内网穿透工具”。还有第三种办法,不花钱,并且在另一层解决它。
登记一个比终端活得更久的地址
平台不需要知道你的笔记本在哪里。它需要的是一个始终都在的 URL。
Stripe / Shopify / GitHub
│
▼
in.anyhook.net/you/dev ← registered once, never changes
│
▼
https://whatever-ngrok-gave-you-today.ngrok-free.app/webhook
平台对接的是永久的那一半。每当穿透重启,你就改一下临时的那一半,只改一个字段,不用碰平台的控制台。改动约一分钟内就会同步到所有边缘节点。
这就是全部思路。本文剩下的部分讲为什么值得花这五分钟,以及它在哪些地方帮不上忙。
在 Shopify 上,这就不只是小口子了
在大多数平台上,一个过期的 URL 只意味着一些你可以忽略的投递失败。在 Shopify 上,它可能意味着丢掉订阅。
通过 Shopify Admin API 创建的订阅,会一直保留创建时的 URL。启动开发服务器,拿到新的穿透地址,而订阅指向的仍然是昨天的地址。Shopify 往那里投递、失败、重试,连续失败到一定次数后,就会彻底删除这个订阅。这下即使你修好了穿透,也什么都收不到了,而这个故障看起来像是“Shopify 不发了”,而不是“我改了 URL”。
WooCommerce 在连续失败超过五次后停用 Webhook。Stripe 在持续失败后停用端点。一个每天都变的 URL,就是一台专门制造连续失败的机器。
付费固定域名做不到的事
固定的穿透域名解决了重新粘贴的问题。它解决不了笔记本合上的那部分。
在前面放一个转发服务,穿透断开期间到达的事件,会在任何投递尝试之前被接收、验证并写入日志。投递到你的机器上会失败,这是预料中的,也没关系。事件还在。
- 回来以后,启动穿透,点击 Replay(重放)。你离开期间失败的事件会被重放到你的处理程序,最早的先发
- 重放不计入你的月度配额,不过有每日上限,并且会消耗你的计算额度
- 你能确切看到平台发了什么,包括请求头和请求体,而不必从一个根本没运行的处理程序去推断
Free 套餐包含一个 App,每月 10,000 个事件、每天 1,000 个,比一个开发循环用得多。在这个套餐上,事件在三天内都可以重放,老实说,这就是它的上限:它是周末的安全网,不是档案库。
它帮不上忙的地方
- 它不能让你的处理程序保持运行。穿透断开期间,投递到那里都会失败。你得到的是日志和 Replay 按钮,而不是投递到一台已经关机的机器上
- 它不是跳过签名验证的理由。平台的原始请求头会原样转发,所以你原来检查的签名,现在检查的还是同一个
- 在生产环境里,穿透应该彻底消失。那是另一个论点,我们在为什么 ngrok 不够用里讲过。ngrok 仍然是开发循环的正确工具;本文只讨论它造成的 URL 频繁变动
设置方法
- 创建一个 App。你会立即得到
in.anyhook.net/{you}/{app} - 把这个 URL 填到平台控制台里,只填一次
- 把转发目标设为你当前的穿透地址
- 在 App 页面发送一个测试事件,看着它到达
明天,当穿透给你一个新地址时,你只改第 3 步,别的都不用动。如果你之后重命名了 App 或账号,旧 URL 会继续路由,而不是返回 404,因为一个已经交给平台的 URL,永远不应该失效。
总结
平台的控制台不该用来存一个每天都变的地址。在那里放一个永久的地址,把临时的部分留在你这一侧,每天的那套流程就会消失,连同它一直在悄悄喂大的投递失败计数。
如果你想看更深入的版本,也就是签名验证如何在重试中保持有效,以及平台已经把你停用时该怎么办,就从验证 Webhook 签名和如何重放 Webhook开始。