Webhook:Claude Code 实战指南
了解webhook:Claude Code 实战. 包含实用技巧和代码示例。
Webhook とは
Webhookは事件発生時にHTTP请求で外部システムに通知する仕組みです。決済完成通知、Git push事件、表单发送など多くの場面で使われます。借助 Claude Code,堅牢なWebhook实现を高效地构建可以。
Webhook接收側の实现
import express from "express";
import crypto from "crypto";
const app = express();
// rawBodyを保持する中间件
app.use("/webhooks", express.raw({ type: "application/json" }));
// 署名验证
function verifyWebhookSignature(
payload: Buffer,
signature: string,
secret: string
): boolean {
const expected = crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
app.post("/webhooks/stripe", async (req, res) => {
const signature = req.headers["stripe-signature"] as string;
const secret = process.env.STRIPE_WEBHOOK_SECRET!;
// 署名验证
if (!verifyWebhookSignature(req.body, signature, secret)) {
return res.status(401).json({ error: "Invalid signature" });
}
const event = JSON.parse(req.body.toString());
// 冪等性チェック
const processed = await redis.get(`webhook:${event.id}`);
if (processed) {
return res.json({ status: "already_processed" });
}
try {
await processWebhookEvent(event);
// 処理済み作为マーク(24时间保持)
await redis.set(`webhook:${event.id}`, "1", "EX", 86400);
res.json({ status: "processed" });
} catch (error) {
console.error("Webhook processing failed:", error);
res.status(500).json({ error: "Processing failed" });
}
});
async function processWebhookEvent(event: any) {
switch (event.type) {
case "payment_intent.succeeded":
await handlePaymentSuccess(event.data.object);
break;
case "customer.subscription.updated":
await handleSubscriptionUpdate(event.data.object);
break;
case "invoice.payment_failed":
await handlePaymentFailed(event.data.object);
break;
default:
console.log(`Unhandled event type: ${event.type}`);
}
}
Webhook发送側の实现
interface WebhookConfig {
id: string;
url: string;
secret: string;
events: string[];
active: boolean;
}
class WebhookSender {
private maxRetries = 3;
private retryDelays = [1000, 5000, 30000]; // ms
async send(
config: WebhookConfig,
event: string,
payload: Record<string, unknown>
): Promise<void> {
const body = JSON.stringify({
id: crypto.randomUUID(),
event,
timestamp: new Date().toISOString(),
data: payload,
});
const signature = this.sign(body, config.secret);
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
try {
const response = await fetch(config.url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Webhook-Signature": `sha256=${signature}`,
"X-Webhook-Event": event,
"X-Webhook-Delivery": crypto.randomUUID(),
},
body,
signal: AbortSignal.timeout(10000),
});
if (response.ok) {
await this.logDelivery(config.id, event, "success", attempt);
return;
}
if (response.status >= 400 && response.status < 500) {
// 客户端错误はリトライしない
await this.logDelivery(config.id, event, "client_error", attempt);
return;
}
throw new Error(`HTTP ${response.status}`);
} catch (error) {
if (attempt < this.maxRetries) {
await new Promise((r) => setTimeout(r, this.retryDelays[attempt]));
} else {
await this.logDelivery(config.id, event, "failed", attempt);
throw error;
}
}
}
}
private sign(payload: string, secret: string): string {
return crypto
.createHmac("sha256", secret)
.update(payload)
.digest("hex");
}
private async logDelivery(
configId: string,
event: string,
status: string,
attempts: number
) {
await prisma.webhookDelivery.create({
data: { configId, event, status, attempts },
});
}
}
Webhook注册API
const router = express.Router();
router.post("/api/webhooks", async (req, res) => {
const { url, events } = req.body;
// URLの验证
try {
const parsed = new URL(url);
if (parsed.protocol !== "https:") {
return res.status(400).json({ error: "HTTPS required" });
}
} catch {
return res.status(400).json({ error: "Invalid URL" });
}
// シークレットの生成
const secret = crypto.randomBytes(32).toString("hex");
const webhook = await prisma.webhookConfig.create({
data: {
url,
events,
secret,
active: true,
userId: req.user!.id,
},
});
// シークレットは创建時のみ返す
res.status(201).json({
id: webhook.id,
url: webhook.url,
events: webhook.events,
secret,
});
});
事件のディスパッチ
class EventDispatcher {
private sender = new WebhookSender();
async dispatch(event: string, payload: Record<string, unknown>) {
// 該当事件を購読しているWebhookを获取
const configs = await prisma.webhookConfig.findMany({
where: {
active: true,
events: { has: event },
},
});
// 并行で发送(队列に入れる場合はBullMQを使用)
const results = await Promise.allSettled(
configs.map((config) => this.sender.send(config, event, payload))
);
const failed = results.filter((r) => r.status === "rejected");
if (failed.length > 0) {
console.error(`${failed.length}/${configs.length} webhooks failed`);
}
}
}
// Usage example
const dispatcher = new EventDispatcher();
// 注文完成時
async function completeOrder(orderId: string) {
const order = await prisma.order.update({
where: { id: orderId },
data: { status: "completed" },
});
await dispatcher.dispatch("order.completed", {
orderId: order.id,
total: order.total,
customerId: order.customerId,
});
}
通过 Claude Codeの活用
Webhook实现を让 Claude Code依頼する例です。异步処理相关内容请参阅作业队列・异步処理、事件设计は事件駆動架构也请参阅。
Webhookシステムを実装して。
- 受信: Stripe/GitHub Webhookの署名検証
- 送信: HMAC署名付き、リトライ機能付き
- 冪等性の保証
- 配信ログとモニタリング
- 登録・管理用のREST API
Webhookの安全相关内容请参阅OWASP Webhook Security。Claude Code的用法请参阅官方文档中可以查看。
总结
Webhookはシステム間联动の重要なパターンです。借助 Claude Code,署名验证、リトライ、冪等性保証を含む堅牢なWebhook基盤を高效地构建可以。
免费 PDF:5 分钟看懂 Claude Code 速查表
只需留下邮箱,我们就会立即把这份 A4 一页速查表 PDF 发送给你。
我们会严格保护你的个人信息,绝不发送垃圾邮件。
把 Claude Code 变成真正能带来结果的工作流
先领取中文说明的免费 PDF,再进入英文商品页选择合适的教材。如果你需要团队落地、流程设计或内容变现支持,也可以直接咨询。
本文作者
Masa
深度使用 Claude Code 的工程师。运营 claudecode-lab.com——一个涵盖 10 种语言、超过 2,000 页内容的科技媒体。
相关文章
Claude Code/Codex 安全 Agent Harness 实战:权限、验证与回滚
用权限策略、执行计划、验证脚本和回滚日志,为 Claude Code 与 Codex 搭建更安全的 AI Agent 工作流。
Claude Code 子代理 (Subagent) 实战模式 10 选
使用 Claude Code 的子代理功能,掌握 10 种实战模式。学习如何使用并行处理、专业化和上下文隔离来加倍开发速度。
Claude Code Agent SDK入门 ― 快速构建自主智能代理
学习如何使用Claude Code Agent SDK构建自主AI代理。涵盖环境搭建、工具定义和多步执行,附带实践代码示例。