Webhook使用指南

Webhook工作原理

  1. 向服务提供商注册你的端点URL
  2. 服务中发生事件(如支付成功)
  3. 服务向你的端点发送HTTP POST请求
  4. 你的服务器处理载荷并返回2xx
  5. 若非2xx,服务重试(指数退避)

HMAC 签名验证

// Node.js — verify Stripe-style webhook signature
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');

  // Use timingSafeEqual to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from('sha256=' + expected)
  );
}

// Express handler
app.post('/webhook', express.raw({type:'application/json'}), (req, res) => {
  const sig = req.headers['x-webhook-signature'];
  if (!verifyWebhook(req.body, sig, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // Process event...
  res.json({ received: true });
});

幂等性——处理重复事件

// Store processed event IDs to prevent duplicate processing
async function processWebhook(eventId, payload) {
  const key = `webhook:${eventId}`;
  const processed = await redis.get(key);

  if (processed) {
    return { status: 'already_processed' };
  }

  // Process the webhook
  await handleEvent(payload);

  // Mark as processed (expire after 24h)
  await redis.setex(key, 86400, '1');
  return { status: 'processed' };
}

重试策略

重试次数延迟累计时间
1立即0s
25s5s
330s35s
45min~5.5min
530min~36min
62h~2.6h
724h~26.6h