Files
tiantian-system/public/docs/webhook.md
2026-04-08 17:10:58 +08:00

6.0 KiB
Raw Blame History

Webhook 事件接入

订阅业务事件处理订单支付、AI 任务完成等异步通知。

🔔 什么是 Webhook

Webhook 是一种「反向 API 调用」机制:

  • 传统 API你 → 平台(主动拉取)
  • Webhook平台 → 你(被动接收)

当某个事件发生时(如支付成功),平台主动通知你的服务器。

📋 可订阅的事件

事件类型 说明
payment.completed 支付完成
payment.failed 支付失败
subscription.created 订阅创建
subscription.cancelled 订阅取消
ai.task.completed AI 任务完成
ai.task.failed AI 任务失败
file.uploaded 文件上传完成
project.created 项目创建
user.invited 用户被邀请
workflow.triggered 工作流触发

🚀 配置 Webhook

步骤 1创建 Webhook 端点

在你的服务器创建一个 API 端点:

// Node.js Express 示例
app.post('/webhook/websopy', express.raw({ type: 'application/json' }), (req, res) => {
  // 验证签名
  const signature = req.headers['x-websopy-signature']
  const timestamp = req.headers['x-websopy-timestamp']
  
  if (!verifySignature(req.body, signature, timestamp)) {
    return res.status(401).send('Invalid signature')
  }
  
  // 处理事件
  const event = JSON.parse(req.body)
  console.log('收到事件:', event.type)
  
  // 立即返回 200重要
  res.status(200).send('OK')
  
  // 异步处理业务逻辑
  processEvent(event)
})

步骤 2在控制台配置

  1. 进入 开发者中心 → Webhook
  2. 点击 添加端点
  3. 填写配置:
配置项 说明
URL 你的服务器地址,如 https://your-server.com/webhook/websopy
事件类型 选择要订阅的事件
密钥 用于验证签名的密钥

步骤 3验证签名

import crypto from 'crypto'

function verifySignature(body, signature, timestamp) {
  const secret = process.env.WEBSOPY_WEBHOOK_SECRET
  
  // 检查时间戳5分钟内有效
  const ts = parseInt(timestamp)
  if (Date.now() - ts > 5 * 60 * 1000) {
    return false
  }
  
  // 计算签名
  const payload = `${timestamp}.${body}`
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex')
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  )
}

📨 事件数据格式

通用结构

{
  "id": "evt_abc123xyz",
  "type": "payment.completed",
  "created_at": "2024-01-15T10:30:00Z",
  "data": {
    // 事件相关数据
  }
}

支付完成事件

{
  "id": "evt_abc123xyz",
  "type": "payment.completed",
  "created_at": "2024-01-15T10:30:00Z",
  "data": {
    "order_id": "ord_xyz789",
    "amount": 29900,
    "currency": "CNY",
    "payment_method": "alipay",
    "status": "completed",
    "user_id": "user_123"
  }
}

AI 任务完成事件

{
  "id": "evt_ai123",
  "type": "ai.task.completed",
  "created_at": "2024-01-15T10:30:00Z",
  "data": {
    "task_id": "task_abc",
    "task_type": "ai_chat",
    "result": {
      "content": "这里是 AI 的回复...",
      "model": "gpt-4",
      "usage": {
        "prompt_tokens": 50,
        "completion_tokens": 120
      }
    },
    "user_id": "user_123"
  }
}

🔧 处理业务逻辑

处理支付事件

async function processPaymentEvent(event) {
  const { order_id, amount, status } = event.data
  
  switch (status) {
    case 'completed':
      // 1. 更新订单状态
      await updateOrderStatus(order_id, 'paid')
      
      // 2. 发放权益
      await grantPremiumAccess(order_id)
      
      // 3. 发送通知
      await sendConfirmationEmail(order_id)
      break
      
    case 'failed':
      // 处理失败
      await handlePaymentFailure(order_id)
      break
  }
}

处理 AI 任务事件

async function processAITaskEvent(event) {
  const { task_id, result, user_id } = event.data
  
  // 保存 AI 回复
  await saveChatMessage({
    taskId: task_id,
    userId: user_id,
    content: result.content,
    model: result.model,
    tokens: result.usage.completion_tokens
  })
  
  // 更新用户用量
  await updateUserUsage(user_id, result.usage)
}

失败重试

如果你的服务器返回非 200 状态码Websopy 会自动重试:

重试次数 延迟
第 1 次 1 分钟
第 2 次 5 分钟
第 3 次 30 分钟
第 4 次 2 小时
第 5 次 12 小时

超过重试次数仍未成功,事件将被标记为失败,可在控制台手动重试。

幂等处理

const processedEvents = new Set()

app.post('/webhook/websopy', async (req, res) => {
  const event = JSON.parse(req.body)
  
  // 幂等检查
  if (processedEvents.has(event.id)) {
    return res.status(200).send('Already processed')
  }
  
  try {
    await processEvent(event)
    processedEvents.add(event.id)
    res.status(200).send('OK')
  } catch (error) {
    // 返回错误,触发重试
    res.status(500).send('Error')
  }
})

🧪 本地开发测试

使用 ngrok

# 安装 ngrok
npm install -g ngrok

# 启动本地服务
ngrok http 3000

# 复制输出的 https URL 到 Webhook 配置
# https://abc123.ngrok.io/webhook/websopy

Webhook 测试工具

控制台提供「发送测试事件」功能,可以手动触发任意事件类型进行测试。

常见问题

Q: 收到重复事件怎么办?

使用事件 ID 做幂等检查,参考上文示例。

Q: 处理超时怎么办?

app.post('/webhook', async (req, res) => {
  // 立即返回
  res.status(200).send('OK')
  
  // 异步处理
  setImmediate(() => processEvent(req.body))  // 使用 setImmediate 不阻塞
})

Q: 如何查看 webhook 日志?

在控制台 → Webhook → 查看每个端点的请求历史和响应状态。


上一步: 流式输出SSE接入
下一步: REST API 完整参考