如何在本地主机上接收 Stripe Webhooks(免去麻烦)
Source: Dev.to
如何在本地(localhost)接收 Stripe Webhook 而不头疼
在开发 Stripe 集成时,最常见的痛点之一就是 如何在本地机器上接收并调试 webhook。传统做法是使用 ngrok 或类似的隧道服务,但这会带来额外的步骤、费用或不稳定性。下面介绍一种更简洁、免费且可靠的方式——使用 Stripe CLI。
目录
前置条件
- 已有 Stripe 账户(如果没有,请先注册)。
- 本地已经有一个运行中的 web 服务器,能够接受
POST请求(例如http://localhost:4242/webhook)。 - 熟悉基本的 Node.js / Express(或你使用的其他语言/框架)代码结构。
安装 Stripe CLI
注意:下面的命令适用于 macOS 与 Linux。Windows 用户可以使用 PowerShell 或 WSL,或直接下载可执行文件。
# macOS (Homebrew)
brew install stripe/stripe-cli/stripe
# Linux (apt)
curl -L https://stripe.com/files/stripe-cli-0.215.0-linux-amd64.tar.gz | tar xz
sudo mv stripe /usr/local/bin/
# Windows (PowerShell)
iwr https://stripe.com/files/stripe-cli-0.215.0-windows-x86_64.zip -OutFile stripe.zip
Expand-Archive .\stripe.zip -DestinationPath $env:USERPROFILE\stripe-cli
安装完成后,运行 stripe version 以确认安装成功。
登录并获取 API 密钥
stripe login
此命令会在浏览器中打开 Stripe 登录页面,完成后 CLI 会自动保存 access token。随后,你可以在本地的 ~/.config/stripe/config.toml(或 Windows 的相应位置)中看到已配置的 API 密钥。
启动本地 webhook 监听
使用 stripe listen 命令可以让 Stripe 将所有 webhook 事件转发到你的本地端点,而不需要任何第三方隧道服务。
stripe listen --forward-to localhost:4242/webhook
运行后,你会看到类似下面的输出:
> Ready! Your webhook endpoint secret is whsec_XXXXXXXXXXXXXXXXXXXXXXXX
> Forwarding events to http://localhost:4242/webhook
whsec_...:这是 Stripe 为本次会话生成的 签名密钥,稍后需要在代码中使用它来验证事件的真实性。--forward-to:指定本地接收 webhook 的完整 URL(包括端口和路径)。
小技巧:如果你的本地服务器运行在不同的端口或路径,只需相应修改
--forward-to参数即可。
在代码中验证签名
下面以 Node.js + Express 为例,演示如何使用官方提供的 stripe 包来验证 webhook 签名。
const express = require('express');
const app = express();
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET; // 上一步得到的 whsec_...
// Stripe 要求原始请求体(raw body)用于签名校验
app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
const sig = req.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
} catch (err) {
console.error(`⚠️ Webhook signature verification failed.`, err.message);
return res.status(400).send(`Webhook Error: ${err.message}`);
}
// 处理不同类型的事件
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
console.log(`💰 PaymentIntent succeeded: ${paymentIntent.id}`);
// TODO: 业务逻辑(如更新订单状态)
break;
// 其他事件...
default:
console.log(`🔔 Received unhandled event type: ${event.type}`);
}
res.json({received: true});
});
app.listen(4242, () => console.log('🚀 Server listening on port 4242'));
关键点:
express.raw({type: 'application/json'}):确保 Express 不会先对请求体进行 JSON 解析,从而保留原始字节用于签名校验。stripe.webhooks.constructEvent:官方提供的安全校验方法。若校验失败,务必返回400,防止伪造请求。
发送测试事件
Stripe CLI 允许你直接触发各种事件,无需实际进行支付流程。
# 触发一次成功的支付意图(payment_intent.succeeded)
stripe trigger payment_intent.succeeded
CLI 会在后台创建一个模拟的 PaymentIntent,并将对应的 webhook 发送到你本地的 /webhook 端点。终端会显示类似:
> Triggered event payment_intent.succeeded
> Sent event to http://localhost:4242/webhook (status: 200)
如果你的代码返回 200,则表示 webhook 已成功接收并处理。
常见问题与故障排除
| 场景 | 可能原因 | 解决方案 |
|---|---|---|
| 收到 404 | 本地服务器未在指定端口运行或路径不匹配 | 确认 stripe listen --forward-to 中的 URL 与服务器路由一致 |
签名校验失败 (Invalid signature header) | 使用了错误的 whsec_ 密钥或请求体被中间件修改 | 重新复制 stripe listen 输出的密钥,确保 express.raw 未被其他中间件覆盖 |
| CLI 报错 “Unable to connect to Stripe” | 本地网络受限或未登录 | 再次运行 stripe login,或检查防火墙/代理设置 |
| 本地服务器卡死 | express.json() 与 express.raw() 同时使用导致冲突 | 只在 webhook 路由使用 express.raw,其他路由可以继续使用 express.json |
| 想在生产环境使用相同代码 | 生产环境不需要 stripe listen,而是直接使用 Stripe Dashboard 配置的 webhook URL | 将 endpointSecret 设置为 Dashboard 中对应的 Signing secret,并移除 stripe listen 相关步骤 |
小结
使用 Stripe CLI,你可以:
- 免除 ngrok/本地隧道 的额外配置。
- 实时获取签名密钥,确保 webhook 的安全性。
- 一键触发各种事件,快速验证业务逻辑。
只需几条命令,就能在本地完成完整的 webhook 开发与调试流程。祝你玩得开心,集成顺利! 🚀
本地测试 Stripe Webhook(使用 Hooklink)
如果你曾经集成过 Stripe 支付,你一定了解其中的流程:Stripe 会向一个 公共 URL 发送 webhook 事件,而你的开发服务器却运行在 localhost:3000。你需要这些事件实时到达本机,以便能够:
- 测试支付流程
- 处理订阅变更
- 调试边缘案例的 payload
在本文中,我将演示如何使用 Hooklink——一种将 webhook 转发到本地的工具,帮助你实现:
- 永久子域名
- 签名验证
- 事件过滤
- 重放功能
为什么不使用常见的变通方案?
| 工具 | 优点 | 缺点 |
|---|---|---|
| Stripe CLI | 开箱即用,适用于 Stripe | 仅适用于 Stripe——需要为 GitHub、Shopify、Slack 等使用其他工具 |
| ngrok | 通用隧道 | 免费套餐的 URL 每次重启都会更改,无法重放 webhook,且没有内置签名验证 |
| Deploy to staging | 公开端点 | 反馈循环慢,失去在本地设置断点的能力 |
步骤详解:从零开始在本机实时接收 Stripe 事件
1. 创建 Hooklink 账户
- 前往 app.hooklink.net/register 并注册。
- 免费计划 包含 每周 2,500 次请求——足够用于开发。
2. 创建 Stripe 端点
-
在 Hooklink 仪表盘,进入 Endpoints → Create Endpoint。
-
选择 Stripe 模板(最快路径):
- Integrations → 找到 Stripe 卡片 → Use Template
对话框会预填以下字段:
| 字段 | 值(示例) |
|---|---|
| Keyword | stripe(你的 URL 将变为 https://stripe‑yourname.hooklink.net) |
| Local target | http://localhost:3000/api/webhooks/stripe |
| Source allowlist | 所有 12 个官方 Stripe webhook IP 段(已预加载) |
| Event filter | 常用事件,如 payment_intent.succeeded、checkout.session.completed、invoice.paid 等。 |
- 将 Local target URL 调整为与你项目的 webhook 路径相匹配,然后点击 Create。
你的端点现在已经在一个 永久且易记的 URL 上可用:
https://stripe-yourname.hooklink.net
注意: 此 URL 永不更改,因此无需在 Stripe 仪表盘中不断更新。
3. 在 Stripe 中注册 Hooklink URL
- 在 Stripe 仪表盘:Developers → Webhooks → Add endpoint。
- 粘贴 Hooklink URL:
https://stripe-yourname.hooklink.net。 - 选择想要接收的事件(例如
payment_intent.succeeded、checkout.session.completed、customer.subscription.created)。 - 点击 Add endpoint。
4. 启用签名验证
Stripe 会在 Stripe-Signature 头部使用 HMAC‑SHA256 对每个 webhook 进行签名。
-
在 Stripe 的 webhook 设置中,复制 Signing secret(以
whsec_开头)。 -
在 Hooklink 的端点设置中,启用 Signature Verification:
- Algorithm: HMAC‑SHA256
- Header:
Stripe-Signature - Signing secret: 粘贴从 Stripe 获得的值
Hooklink 能原生解析 Stripe 的签名格式 (t=timestamp,v1=signature),构造签名负载为 {timestamp}.{body},并进行恒定时间比较。它还会根据可配置的容差窗口(默认 5 分钟)检查时间戳,以防重放攻击。
5. 安装并登录 Hooklink CLI
# 全局安装
npm install -g @hooklink/cli
在 Dashboard → API Keys 生成 API 密钥,然后登录:
hooklink login --key hlk_your_api_key_here
6. 连接到你的 Stripe 端点
hooklink connect stripe
你会看到类似以下的输出:
$ hooklink connect stripe
Connection Details:
Version: v1.2.0
Endpoint: stripe
Webhook URL: https://stripe-yourname.hooklink.net
Target: http://localhost:3000/api/webhooks/stripe
Waiting for webhooks...
现在,每个 Stripe webhook 都会通过持久的 WebSocket 连接实时转发到你的本地服务器。
7. 测试整个流程
- 在 Stripe 的 webhook 设置中,点击 Send test webhook 并选择一个事件(例如
payment_intent.succeeded)。 - 在终端中你会看到:
stripe POST --> payment_intent.succeeded
stripe POST payment_intent.succeeded
stripe POST push
github POST <-- 200 8ms
preview GET /dashboard 200
安装
npm install -g @hooklink/cli
身份验证
hooklink login --key hlk_your_key
连接到端点
-
单个端点(Stripe)
hooklink connect stripe -
多个端点(Stripe、GitHub、Preview)
hooklink connect stripe,github,preview
实用命令
-
查看最近的 webhook 日志
hooklink logs --endpoint stripe -
检查连接状态
hooklink status
为什么使用 Hooklink?
在本地测试 Stripe webhook 不必痛苦。使用 Hooklink,你可以获得:
- 一个 永久 URL,即使重启也能保持
- 内置的 Stripe 签名验证
- 事件过滤 和 来源 IP 白名单
- 一键 webhook 重放
- 免费的完整请求日志
免费套餐提供 每周 2,500 次请求,覆盖 3 个端点,并包含完整请求日志——足以满足大多数开发工作流的需求。
快速开始(无需注册)
npx @hooklink/cli listen 3000
30 秒内即可拥有一个公开的 webhook URL。