PAYWISE
zh
← 全部文章

开发者

Webhook 与重定向:为什么付款状态必须以 Webhook 为准,而不是成功页面

返回 URL 告诉顾客发生了什么;带签名的 Webhook 告诉您的服务器。为什么绝不能根据重定向来处理订单(附代码)。

发布于 11 十月 2026 阅读约 3 分钟

其他语言版本: English, Indonesia

Webhook 与重定向:为什么付款状态必须以 Webhook 为准,而不是成功页面

顾客付款后,几乎同时会发生两件事:

  1. PAYWISE 把顾客送回您的网站(重定向,即返回 URL)。
  2. PAYWISE 向您的服务器发送带签名的 Webhook(回调)。

两者看起来相似,用途却截然不同。把它们混淆是最常见、也最昂贵的集成错误之一。

两条消息,两种用途:带签名的 Webhook 在您的服务器上更新订单,重定向只向顾客显示感谢页面

重定向:给顾客看的

当付款变为已付款、已过期或失败时,托管支付页面会把顾客送到您的返回 URL,并附上结果:

https://shop.example.com/thanks?reference=PW20260921143022AB3F&merchant_reference=ORDER-1042&status=paid

这个 URL 不能证明任何事情。任何人都可以在浏览器中输入它,把 status=failed 改成 status=paid,然后按回车。如果您的店铺在打开此页面时就把订单标记为已付款,任何人都能免费拿走您的商品。

重定向也可能根本不会发生:顾客关闭了标签页、网络断开,或在手机上付款后再也没有返回。

重定向只用来显示消息:"感谢您,我们正在确认您的付款。"

Webhook:给服务器的

Webhook 是 PAYWISE 发往您服务器的 POST 请求,属于服务器到服务器的通信。它在 X-PAYWISE-Signature 请求头中使用您的 Webhook 密钥签名,因此您的服务器可以确认它确实来自 PAYWISE 且未被篡改。即使顾客关闭了标签页它也会送达,发送失败时还会自动重试。

应该在 Webhook 中将订单标记为已付款并开始履约。签名验证方法见 验证 PAYWISE Webhook 签名。

两者如何配合

**Webhook 处理程序:**先验证,再只更新一次订单。

$raw = file_get_contents('php://input');
$event = \Paywise\Webhook::parse($raw, $_SERVER['HTTP_X_PAYWISE_SIGNATURE'] ?? '', getenv('PAYWISE_WEBHOOK_SECRET'));

if ($event['event'] === 'payment.paid') {
    // 只更新仍未付款的订单:重复送达不会改变任何东西。
    $db->prepare("UPDATE orders SET status = 'paid' WHERE paywise_reference = ? AND status = 'unpaid'")
       ->execute([$event['data']['reference']]);
}
http_response_code(200);

感谢页面:从您自己的数据库读取状态,而不是从 URL 读取。

$order = findOrderByPaywiseReference($_GET['reference'] ?? '');
if ($order && $order->status === 'paid') {
    echo '感谢您!订单已确认。';
} else {
    echo '感谢您!我们正在确认您的付款,页面稍后会自动更新。';
}

如果顾客到达页面时 Webhook 还没送达,可以几秒后刷新页面,或直接用 GET /api/v1/transactions/{reference} 向 PAYWISE 查询。该请求使用您的 API 密钥认证,因此结果可信。

检查清单

  • 只根据经过验证的 payment.paid Webhook,或 GET /api/v1/transactions/{reference} 返回 paid 后才处理订单。
  • 绝不信任返回 URL 中的 status。
  • 让 Webhook 处理程序具备幂等性:同一事件可能送达多次。
  • 尽快以 2xx 响应 Webhook;耗时的工作(发邮件、更新库存)放在之后处理。
  • 在沙盒中测试三种结果。参见 上线前测试 Webhook 端点。

更多文章

今天就从沙盒密钥开始。

创建账户、生成沙盒密钥,几分钟内即可在调试台发送第一笔交易。