Skip to content

回调(webhook)是什么,为什么必须配 ​

不配的结果:买家付了钱,订单还是「待付款」

然后被超时关单。钱收了,货没发,买家来投诉。

这是所有支付接入里最常见、也最贵的一个漏配。

它解决什么问题 ​

买家点「支付」之后会离开你的网站(跳到 Stripe 或 PayPal 的页面)。付完款他会跳回来, 但你的服务器并不知道这笔钱到底有没有付成功 ——

  • 他可能付完就关掉了浏览器,根本没跳回来
  • 跳回来的那个页面参数是买家浏览器带回来的,可以被伪造

所以真正可信的只有一条路:支付平台的服务器主动打一个请求到你的服务器, 告诉你"订单 X 已付款"。这个请求就是 webhook(回调)。

支付成功页看到的状态是"轮询"出来的

买家跳回来时,页面会每隔一两秒问一次后端"这单付了吗"。 真正把订单改成已付款的,是 webhook。

所以你会看到支付页短暂显示"处理中" —— 那是在等 webhook 到达,是正常的。

回调地址从哪儿拿 ​

Alipay+ / Antom 不用配这一步

它的回调地址是系统在每一笔请求里自己带过去的,你不需要去 Antom 后台建端点。整篇下面讲的都是 Stripe / PayPal。 见 Alipay+ / Antom 配置。

不用自己拼,后台直接给你

站点管理 → 支付通道,每一行都有一列**「回调地址(webhook)」, 后面有个复制**按钮。点一下,直接去支付平台粘上就行。

配置密钥的弹窗里,「密钥」那一段上面也有同一个地址和复制按钮 —— 因为填 Webhook 签名密钥的前提,就是先拿这个地址去平台建端点。

它长这样:

https://你的域名/api/open/payment/callback/{provider}/{通道ID}

实际例子:

https://jdz.io/api/open/payment/callback/stripe/3

顺序:先建通道并保存 → 再复制地址去配回调

地址里带着通道 ID,而 ID 是保存之后才有的。

所以新建通道时,那个弹窗里会提示「回调地址要保存之后才有」—— 先把密钥填上保存一次,再打开编辑,就能复制到地址了。

用复制按钮,别手打

手拼最常见的三种错:

  • 漏掉 /api/open/ 这一段
  • provider 写成 Stripe(要小写 stripe)
  • 域名写成了后台地址

每一种的结果都是支付平台收到 404,而你看到的只是"订单一直待付款", 完全联想不到是地址拼错了。

每个通道一个地址

沙箱通道和正式通道是两个不同的 ID,所以是两个不同的回调地址, 要在支付平台的沙箱环境和正式环境各配一次。

漏配正式环境的那次,是上线当天最典型的事故。

系统怎么保证回调是真的 ​

你可能会想:这个地址是公开的,别人随便打一下不就能伪造"已付款"?

系统做了这几层:

检查作用
验签用你填的 Webhook 密钥校验报文签名。签名不对 → 401 拒绝
验时间戳超过 5 分钟的报文拒收 —— 否则截获一条"支付成功"就能无限重放
金额校验回调里的金额和订单金额对不上 → 拒绝
幂等同一笔支付重复回调只认一次

所以 Webhook 密钥必须填对

不填或填错的话,所有回调都会被判为伪造并拒绝 —— 表现和"没配回调"一模一样:订单永远是待付款。

平台会重推,这是好事 ​

网络抖动、或者你正好在重启后端时,回调会失败。 支付平台会自动重试(Stripe 会重试几天)。

系统对重复回调是幂等的,重推不会造成重复加款。

万一重试次数用完了还是没送到?

系统有一个主动查单补偿任务:定时去支付平台问"这几笔待付款的单到底付了没", 付了就补上。所以即使 webhook 全丢了,订单最终也能自愈。

但这只是兜底,不能拿它当主要路径 —— 补偿任务有间隔, 买家付完钱要等好几分钟才看到订单变化,体验很差。

怎么确认回调配好了 ​

方法 1:看支付平台的回调日志(最准) ​

  • Stripe:Developers → Webhooks → 点你配的那个端点 → 下面有每次投递的记录
    • 200 = 我们收到了并处理成功
    • 401 = 验签失败,多半是 Webhook 密钥填错
    • 404 = 地址写错了(通道 ID 不对?域名不对?)
    • 超时 / 连不上 = 域名解析或服务器的问题
  • PayPal:Developer Dashboard → 你的 App → Webhooks → Event logs

方法 2:走一遍沙箱支付 ​

用测试卡付一笔,看订单几秒内是不是变成「已付款」。

变了但很慢(超过 1 分钟)

那多半不是 webhook 起的作用,而是补偿任务兜底了。 去看平台的回调日志,确认那条 webhook 的响应码。

常见问题 ​

平台日志显示 401

Webhook 密钥填错了。

  • Stripe:那串是 whsec_...,在你添加端点之后才会生成, 在端点详情页里点「Reveal」才看得到 —— 不是 API keys 页面上的那两个
  • 换过端点、删了重建过端点,密钥会变,要回后台更新

平台日志显示 404

基本都是手拼地址拼错了。回后台用「复制」按钮重新取一次, 覆盖掉支付平台上那条端点的地址。

如果复制的地址也是 404:

  1. 域名对吗 —— 后台的地址栏域名必须是能从公网访问的正式域名
  2. 通道还在吗 —— 通道被删过的话 ID 就失效了(正常操作是"停用"不是删)

本地开发时怎么测回调

支付平台打不到你的电脑。用 Stripe CLI 的 stripe listen --forward-to 把回调转发到本机, 或者用 ngrok 之类的内网穿透。

但没必要在本地折腾这个 —— 直接在服务器上用沙箱通道测更省事。

除了验签失败,系统一律返回 2xx

即使我们内部处理出错,也会返回 2xx。

为什么:返非 2xx 只会让平台反复重推,把"一单出错"放大成"每分钟几百次请求"。 出错的信息记在服务器日志里(/opt/mall/logs/mall.log),不靠 HTTP 状态码传递。

这份文档只讲后台怎么用,不含任何真实密钥