综合 回调打不到本地:cloudflared quick tunnel 的 200 并发与 SSE 限制,换 zrok 之前先看清

2026-10-31 21:32:24

商户后台的回调地址只接受公网 HTTPS,本地 localhost:8080 收不到任何通知——联调第一步是把本地服务挂到一个公网 URL 上。

一、cloudflared quick tunnel:安装后一条命令

项目:cloudflare/cloudflared
文档:Cloudflare Quick Tunnels

Quick Tunnels 会给本地服务生成一个临时的 trycloudflare.com URL,不需要 Cloudflare 账号,也不需要自己的域名。官方定位是测试与开发用途;生产环境应创建正式的 Cloudflare Tunnel。

前置条件:安装 cloudflared,本地起一个 HTTP 服务(文档示例用 http://localhost:8080)。

cloudflared tunnel --url http://localhost:8080

执行后终端会打印一个 trycloudflare.com URL,打开即可访问本地服务。任何拿到这个 URL 的人都能访问;停止 cloudflared 进程,URL 随之失效。

用 --allowed-mail 限制访问者

单个邮箱:

cloudflared tunnel --url http://localhost:8080 --allowed-mail alice@example.com

多个邮箱,重复 flag:

cloudflared tunnel --url http://localhost:8080 --allowed-mail alice@example.com --allowed-mail bob@example.com

或者逗号分隔:

cloudflared tunnel --url http://localhost:8080 --allowed-mail 'alice@example.com,bob@example.com'

放开整个域用 *@example.com,需要加引号防止 shell 展开:

cloudflared tunnel --url http://localhost:8080 --allowed-mail '*@example.com'

访问者打开 URL 后填邮箱,收到一次性 PIN 输入即可进入,不需要 Cloudflare 账号。要改允许名单只能停掉 cloudflared 重建隧道;进程停止后所有人的访问同时结束。

二、官方列出的限制

  • 没有 uptime 保证。
  • 每个 Quick Tunnel 最多 200 个 in-flight 请求,超出的请求返回 429。
  • 不支持 Server-Sent Events(SSE)。
  • 邮箱验证需要交互式浏览器会话,不支持非交互客户端。
  • 每次创建 Quick Tunnel,hostname 都会变。
  • 需要稳定 hostname 和生产流量,请创建 Cloudflare Tunnel。

三、逐条落到回调联调上

hostname 每次变。 每次重启 cloudflared 都要回商户后台重填回调地址,本地那份回调 URL 校验配置也要跟着改。地址没同步时,签名逻辑可能是对的,但商户侧比对地址失败。

200 in-flight / 429。 在商户后台点「重发通知」批量回放历史回调,或者本地做并发压测时,很容易撞到 429。对端看到的是投递失败,会进入重试,日志里随后出现同一笔通知的重复记录。

不支持 SSE。 如果本地调试页用 SSE 实时滚动回调日志,走 quick tunnel 这条链路是不通的,只能直连 localhost 看,或把推送方式换成轮询。

邮箱验证需要交互式浏览器。 用 curl、Postman 或商户服务器发起的回调都是非交互客户端,无法完成一次性 PIN 这一步,因此 --allowed-mail 与「让商户服务器把回调打进来」这件事本身是矛盾的;实际叠加行为需自行验证。

无 uptime 保证、进程停即失效。 联调窗口之外隧道掉线,商户后台的失败重试可能继续跑一段时间,隧道恢复后要重新核对一遍通知状态。

四、换一条路:zrok

仓库:openziti/zrok
文档:docs.zrok.io

zrok 用来在公网或私有网络内共享 web 服务、文件和网络资源,构建在 OpenZiti(可编程零信任网络 overlay)之上,穿过防火墙和 NAT 不需要改网络配置。全链路加密(包括经过 zrok 服务器的那一段),条件允许时走 peer-to-peer,访问控制按身份而不是 IP。

安装见 安装指引,然后拿账号并启用:

zrok invite    # 使用免费的 zrok.io 服务
zrok enable
# 公开分享一个 web 服务
zrok share public localhost:8080

# 把一个目录当作网络盘分享
zrok share public --backend-mode drive ~/Documents

# 只分享给其他 zrok 用户
zrok share private localhost:3000

私有资源可以把 TCP/UDP 服务共享给指定的 zrok 用户,不暴露在公网。支持 HTTP/HTTPS、TCP、UDP 和文件分享,覆盖 Windows / macOS / Linux / 树莓派。可自托管:单二进制包含全部组件,官方 zrok.io 服务与自托管用的是同一套代码。

Go SDK 创建分享:

shr, err := sdk.CreateShare(root, &sdk.ShareRequest{
    BackendMode: sdk.TcpTunnelBackendMode,
    ShareMode:   sdk.PrivateShareMode,
})
listener, err := sdk.NewListener(shr.Token, root)

五、三条路径对照

cloudflared quick tunnelzrok 公共(zrok.io)zrok 自建
账号 / 域名不需要账号和域名需要 zrok invite 拿账号需要自建实例与账号体系
公网 URL每次新建都变需自行验证需自行验证
SSE不支持需自行验证需自行验证
并发上限200 in-flight,超出 429需自行验证需自行验证
访问控制可选邮箱 PIN(需交互浏览器)公开 / 私有分享,按身份授权同左
协议HTTPHTTP/HTTPS、TCP、UDP、文件同左
端到端加密需自行验证默认开启默认开启
托管Cloudflarezrok.io自己

取舍:只做短时验证、能接受每次换地址,cloudflared tunnel --url 起得最快;需要稳定入口、要让 SSE 日志和批量回调回放跑通、或者不希望回调流量经过第三方服务,用 zrok,长期联调建议自建。

六、联调侧三条硬提醒

  1. 回调必须用 raw body 验签。 框架先把 JSON 解析成对象再序列化,字节级内容会变(字段顺序、空格、转义),签名对不上。验签前保留原始请求体。
  2. 回调地址与密钥按环境分开。 测试商户号、测试密钥单独一份配置,不要和生产共用同一个文件或同一套环境变量。
  3. 不要拿 quick tunnel 当生产回调入口。 无 uptime 保证、hostname 每次重建都变、200 in-flight 的 429 和不支持 SSE 都写在上面的限制清单里,这些与回调链路的稳定性要求直接冲突。
复制全文 生成海报 接口对接 webhook 联调工具 zrok

推荐文章

程序员茄子在线接单