Webhooks API
本文档描述了 Trae Webhooks 功能的 API 接口。
概述
Webhooks 允许您在特定事件发生时接收实时通知。当事件触发时,Trae 会向您配置的 URL 发送 HTTP POST 请求,包含事件的详细信息。
支持的事件
| 事件类型 | 描述 |
|---|---|
project.created | 项目创建 |
project.updated | 项目更新 |
project.deleted | 项目删除 |
build.started | 构建开始 |
build.completed | 构建完成 |
build.failed | 构建失败 |
deployment.started | 部署开始 |
deployment.completed | 部署完成 |
deployment.failed | 部署失败 |
collaboration.invited | 协作邀请 |
collaboration.joined | 加入协作 |
collaboration.left | 离开协作 |
file.created | 文件创建 |
file.updated | 文件更新 |
file.deleted | 文件删除 |
user.registered | 用户注册 |
user.login | 用户登录 |
user.logout | 用户登出 |
security.alert | 安全警报 |
端点
创建 Webhook
http
POST /api/webhooks请求参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
url | string | 是 | Webhook 接收 URL |
events | array | 是 | 订阅的事件类型列表 |
name | string | 是 | Webhook 名称 |
description | string | 否 | Webhook 描述 |
secret | string | 否 | 用于验证的密钥 |
active | boolean | 否 | 是否激活 (默认: true) |
project_id | string | 否 | 项目 ID (项目级别 webhook) |
headers | object | 否 | 自定义请求头 |
timeout | number | 否 | 超时时间 (秒, 默认: 30) |
retry_policy | object | 否 | 重试策略 |
请求示例
json
{
"url": "https://api.example.com/webhooks/trae",
"events": [
"build.completed",
"build.failed",
"deployment.completed",
"deployment.failed"
],
"name": "CI/CD Notifications",
"description": "Receive notifications for build and deployment events",
"secret": "your-webhook-secret-key",
"active": true,
"project_id": "proj_123",
"headers": {
"X-Custom-Header": "custom-value",
"Authorization": "Bearer your-api-token"
},
"timeout": 30,
"retry_policy": {
"max_attempts": 3,
"backoff_strategy": "exponential",
"initial_delay": 1000,
"max_delay": 60000
}
}响应
json
{
"webhook_id": "webhook_456",
"url": "https://api.example.com/webhooks/trae",
"events": [
"build.completed",
"build.failed",
"deployment.completed",
"deployment.failed"
],
"name": "CI/CD Notifications",
"description": "Receive notifications for build and deployment events",
"secret": "your-webhook-secret-key",
"active": true,
"project_id": "proj_123",
"headers": {
"X-Custom-Header": "custom-value",
"Authorization": "Bearer your-api-token"
},
"timeout": 30,
"retry_policy": {
"max_attempts": 3,
"backoff_strategy": "exponential",
"initial_delay": 1000,
"max_delay": 60000
},
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z",
"created_by": "user_123",
"stats": {
"total_deliveries": 0,
"successful_deliveries": 0,
"failed_deliveries": 0,
"last_delivery": null
}
}获取 Webhook 列表
http
GET /api/webhooks?project_id={project_id}&active={active}&limit={limit}&offset={offset}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
project_id | string | 否 | 项目 ID 过滤 |
active | boolean | 否 | 激活状态过滤 |
limit | number | 否 | 返回数量限制 |
offset | number | 否 | 偏移量 |
sort | string | 否 | 排序字段 |
order | string | 否 | 排序方向 (asc/desc) |
响应
json
{
"webhooks": [
{
"webhook_id": "webhook_456",
"url": "https://api.example.com/webhooks/trae",
"events": [
"build.completed",
"build.failed"
],
"name": "CI/CD Notifications",
"description": "Receive notifications for build and deployment events",
"active": true,
"project_id": "proj_123",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z",
"created_by": "user_123",
"stats": {
"total_deliveries": 150,
"successful_deliveries": 145,
"failed_deliveries": 5,
"last_delivery": "2024-01-01T11:30:00Z",
"success_rate": 96.67
}
}
],
"total": 1,
"pagination": {
"limit": 20,
"offset": 0,
"has_more": false
}
}获取特定 Webhook
http
GET /api/webhooks/{webhook_id}响应
json
{
"webhook_id": "webhook_456",
"url": "https://api.example.com/webhooks/trae",
"events": [
"build.completed",
"build.failed",
"deployment.completed",
"deployment.failed"
],
"name": "CI/CD Notifications",
"description": "Receive notifications for build and deployment events",
"secret": "your-webhook-secret-key",
"active": true,
"project_id": "proj_123",
"headers": {
"X-Custom-Header": "custom-value",
"Authorization": "Bearer your-api-token"
},
"timeout": 30,
"retry_policy": {
"max_attempts": 3,
"backoff_strategy": "exponential",
"initial_delay": 1000,
"max_delay": 60000
},
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z",
"created_by": "user_123",
"stats": {
"total_deliveries": 150,
"successful_deliveries": 145,
"failed_deliveries": 5,
"last_delivery": "2024-01-01T11:30:00Z",
"success_rate": 96.67,
"average_response_time": 250
},
"recent_deliveries": [
{
"delivery_id": "del_789",
"event_type": "build.completed",
"status": "success",
"response_code": 200,
"response_time": 245,
"delivered_at": "2024-01-01T11:30:00Z",
"attempts": 1
},
{
"delivery_id": "del_788",
"event_type": "build.failed",
"status": "failed",
"response_code": 500,
"response_time": 5000,
"delivered_at": "2024-01-01T11:00:00Z",
"attempts": 3,
"error": "Internal Server Error"
}
]
}更新 Webhook
http
PUT /api/webhooks/{webhook_id}请求参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
url | string | 否 | Webhook 接收 URL |
events | array | 否 | 订阅的事件类型列表 |
name | string | 否 | Webhook 名称 |
description | string | 否 | Webhook 描述 |
secret | string | 否 | 用于验证的密钥 |
active | boolean | 否 | 是否激活 |
headers | object | 否 | 自定义请求头 |
timeout | number | 否 | 超时时间 (秒) |
retry_policy | object | 否 | 重试策略 |
请求示例
json
{
"events": [
"build.completed",
"build.failed",
"deployment.completed",
"deployment.failed",
"security.alert"
],
"active": true,
"timeout": 45,
"retry_policy": {
"max_attempts": 5,
"backoff_strategy": "exponential",
"initial_delay": 2000,
"max_delay": 120000
}
}响应
json
{
"webhook_id": "webhook_456",
"url": "https://api.example.com/webhooks/trae",
"events": [
"build.completed",
"build.failed",
"deployment.completed",
"deployment.failed",
"security.alert"
],
"name": "CI/CD Notifications",
"description": "Receive notifications for build and deployment events",
"active": true,
"timeout": 45,
"retry_policy": {
"max_attempts": 5,
"backoff_strategy": "exponential",
"initial_delay": 2000,
"max_delay": 120000
},
"updated_at": "2024-01-01T12:30:00Z"
}删除 Webhook
http
DELETE /api/webhooks/{webhook_id}响应
json
{
"message": "Webhook deleted successfully",
"webhook_id": "webhook_456",
"deleted_at": "2024-01-01T12:00:00Z"
}测试 Webhook
http
POST /api/webhooks/{webhook_id}/test请求参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
event_type | string | 否 | 测试事件类型 (默认: test.ping) |
payload | object | 否 | 自定义测试载荷 |
请求示例
json
{
"event_type": "build.completed",
"payload": {
"build_id": "build_test_123",
"project_id": "proj_123",
"status": "success",
"duration": 120
}
}响应
json
{
"delivery_id": "del_test_999",
"event_type": "build.completed",
"status": "success",
"response_code": 200,
"response_time": 245,
"response_body": "OK",
"delivered_at": "2024-01-01T12:00:00Z",
"attempts": 1,
"webhook_url": "https://api.example.com/webhooks/trae"
}获取 Webhook 投递历史
http
GET /api/webhooks/{webhook_id}/deliveries?limit={limit}&offset={offset}&status={status}&event_type={event_type}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
limit | number | 否 | 返回数量限制 |
offset | number | 否 | 偏移量 |
status | string | 否 | 投递状态过滤 (success/failed/pending) |
event_type | string | 否 | 事件类型过滤 |
start_date | string | 否 | 开始日期 (ISO 8601) |
end_date | string | 否 | 结束日期 (ISO 8601) |
响应
json
{
"deliveries": [
{
"delivery_id": "del_789",
"webhook_id": "webhook_456",
"event_type": "build.completed",
"event_id": "event_123",
"status": "success",
"response_code": 200,
"response_time": 245,
"response_body": "OK",
"delivered_at": "2024-01-01T11:30:00Z",
"attempts": 1,
"payload": {
"event": "build.completed",
"timestamp": "2024-01-01T11:30:00Z",
"data": {
"build_id": "build_123",
"project_id": "proj_123",
"status": "success",
"duration": 120,
"commit_sha": "abc123def456",
"branch": "main"
}
}
},
{
"delivery_id": "del_788",
"webhook_id": "webhook_456",
"event_type": "build.failed",
"event_id": "event_122",
"status": "failed",
"response_code": 500,
"response_time": 5000,
"response_body": "Internal Server Error",
"delivered_at": "2024-01-01T11:00:00Z",
"attempts": 3,
"error": "HTTP 500: Internal Server Error",
"next_retry": null,
"payload": {
"event": "build.failed",
"timestamp": "2024-01-01T11:00:00Z",
"data": {
"build_id": "build_122",
"project_id": "proj_123",
"status": "failed",
"error": "Compilation error in main.js",
"commit_sha": "def456ghi789",
"branch": "feature/new-ui"
}
}
}
],
"total": 2,
"pagination": {
"limit": 20,
"offset": 0,
"has_more": false
},
"stats": {
"total_deliveries": 150,
"successful_deliveries": 145,
"failed_deliveries": 5,
"pending_deliveries": 0,
"success_rate": 96.67
}
}重新投递 Webhook
http
POST /api/webhooks/{webhook_id}/deliveries/{delivery_id}/redeliver响应
json
{
"delivery_id": "del_new_999",
"original_delivery_id": "del_788",
"event_type": "build.failed",
"status": "pending",
"scheduled_at": "2024-01-01T12:00:00Z",
"webhook_url": "https://api.example.com/webhooks/trae"
}获取 Webhook 统计
http
GET /api/webhooks/{webhook_id}/stats?period={period}&start_date={start_date}&end_date={end_date}查询参数
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
period | string | 否 | 统计周期 (hour/day/week/month) |
start_date | string | 否 | 开始日期 (ISO 8601) |
end_date | string | 否 | 结束日期 (ISO 8601) |
响应
json
{
"webhook_id": "webhook_456",
"period": "day",
"start_date": "2024-01-01T00:00:00Z",
"end_date": "2024-01-07T23:59:59Z",
"overall_stats": {
"total_deliveries": 150,
"successful_deliveries": 145,
"failed_deliveries": 5,
"pending_deliveries": 0,
"success_rate": 96.67,
"average_response_time": 250,
"median_response_time": 200,
"p95_response_time": 500
},
"daily_stats": [
{
"date": "2024-01-01",
"total_deliveries": 25,
"successful_deliveries": 24,
"failed_deliveries": 1,
"success_rate": 96.0,
"average_response_time": 245
},
{
"date": "2024-01-02",
"total_deliveries": 30,
"successful_deliveries": 29,
"failed_deliveries": 1,
"success_rate": 96.67,
"average_response_time": 230
}
],
"event_type_stats": [
{
"event_type": "build.completed",
"total_deliveries": 80,
"successful_deliveries": 78,
"failed_deliveries": 2,
"success_rate": 97.5
},
{
"event_type": "build.failed",
"total_deliveries": 20,
"successful_deliveries": 19,
"failed_deliveries": 1,
"success_rate": 95.0
},
{
"event_type": "deployment.completed",
"total_deliveries": 30,
"successful_deliveries": 29,
"failed_deliveries": 1,
"success_rate": 96.67
},
{
"event_type": "deployment.failed",
"total_deliveries": 20,
"successful_deliveries": 19,
"failed_deliveries": 1,
"success_rate": 95.0
}
]
}Webhook 载荷格式
所有 Webhook 载荷都遵循以下基本格式:
json
{
"event": "event.type",
"timestamp": "2024-01-01T12:00:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_789",
"data": {
// 事件特定数据
}
}构建事件载荷
build.started
json
{
"event": "build.started",
"timestamp": "2024-01-01T12:00:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_789",
"data": {
"build_id": "build_123",
"project_id": "proj_123",
"project_name": "My Project",
"commit_sha": "abc123def456",
"commit_message": "Fix bug in authentication",
"branch": "main",
"author": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"trigger": "push",
"started_at": "2024-01-01T12:00:00Z",
"environment": "production",
"build_config": {
"node_version": "18.x",
"build_command": "npm run build",
"output_directory": "dist"
}
}
}build.completed
json
{
"event": "build.completed",
"timestamp": "2024-01-01T12:02:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_790",
"data": {
"build_id": "build_123",
"project_id": "proj_123",
"project_name": "My Project",
"commit_sha": "abc123def456",
"commit_message": "Fix bug in authentication",
"branch": "main",
"author": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"status": "success",
"started_at": "2024-01-01T12:00:00Z",
"completed_at": "2024-01-01T12:02:00Z",
"duration": 120,
"environment": "production",
"artifacts": [
{
"name": "build-output.zip",
"size": 1024576,
"url": "https://cdn.trae.ai/builds/build_123/artifacts/build-output.zip"
}
],
"logs_url": "https://app.trae.ai/projects/proj_123/builds/build_123/logs",
"deploy_preview_url": "https://build-123--my-project.trae.app"
}
}build.failed
json
{
"event": "build.failed",
"timestamp": "2024-01-01T12:01:30Z",
"webhook_id": "webhook_456",
"delivery_id": "del_791",
"data": {
"build_id": "build_124",
"project_id": "proj_123",
"project_name": "My Project",
"commit_sha": "def456ghi789",
"commit_message": "Add new feature",
"branch": "feature/new-ui",
"author": {
"name": "Bob Smith",
"email": "bob@example.com",
"username": "bob_dev"
},
"status": "failed",
"started_at": "2024-01-01T12:00:00Z",
"failed_at": "2024-01-01T12:01:30Z",
"duration": 90,
"environment": "production",
"error": {
"type": "compilation_error",
"message": "Compilation failed: Unexpected token in main.js:45",
"details": {
"file": "src/main.js",
"line": 45,
"column": 12,
"code": "SyntaxError"
}
},
"logs_url": "https://app.trae.ai/projects/proj_123/builds/build_124/logs"
}
}部署事件载荷
deployment.completed
json
{
"event": "deployment.completed",
"timestamp": "2024-01-01T12:05:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_792",
"data": {
"deployment_id": "deploy_123",
"build_id": "build_123",
"project_id": "proj_123",
"project_name": "My Project",
"environment": "production",
"status": "success",
"started_at": "2024-01-01T12:03:00Z",
"completed_at": "2024-01-01T12:05:00Z",
"duration": 120,
"url": "https://my-project.trae.app",
"commit_sha": "abc123def456",
"commit_message": "Fix bug in authentication",
"branch": "main",
"author": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"deployed_by": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"deployment_config": {
"strategy": "rolling",
"instances": 3,
"health_check_url": "/health"
}
}
}协作事件载荷
collaboration.invited
json
{
"event": "collaboration.invited",
"timestamp": "2024-01-01T12:00:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_793",
"data": {
"invitation_id": "invite_123",
"project_id": "proj_123",
"project_name": "My Project",
"inviter": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"invitee": {
"email": "bob@example.com",
"name": "Bob Smith"
},
"role": "developer",
"permissions": [
"read",
"write",
"build"
],
"message": "Welcome to the team! Looking forward to working with you.",
"expires_at": "2024-01-08T12:00:00Z",
"invitation_url": "https://app.trae.ai/invitations/invite_123"
}
}文件事件载荷
file.updated
json
{
"event": "file.updated",
"timestamp": "2024-01-01T12:00:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_794",
"data": {
"file_id": "file_123",
"project_id": "proj_123",
"project_name": "My Project",
"file_path": "src/components/Button.jsx",
"file_name": "Button.jsx",
"file_type": "javascript",
"size": 2048,
"updated_by": {
"name": "Alice Johnson",
"email": "alice@example.com",
"username": "alice_dev"
},
"changes": {
"lines_added": 15,
"lines_removed": 8,
"lines_modified": 3
},
"commit_sha": "abc123def456",
"branch": "feature/button-improvements",
"diff_url": "https://app.trae.ai/projects/proj_123/files/file_123/diff"
}
}安全事件载荷
security.alert
json
{
"event": "security.alert",
"timestamp": "2024-01-01T12:00:00Z",
"webhook_id": "webhook_456",
"delivery_id": "del_795",
"data": {
"alert_id": "alert_123",
"alert_type": "suspicious_login",
"severity": "high",
"title": "Suspicious login attempt detected",
"description": "Multiple failed login attempts from unusual location",
"user": {
"user_id": "user_123",
"username": "alice_dev",
"email": "alice@example.com"
},
"details": {
"ip_address": "203.0.113.1",
"location": "Unknown Location",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"failed_attempts": 5,
"time_window": "5 minutes"
},
"actions_taken": [
"account_locked",
"notification_sent"
],
"recommended_actions": [
"change_password",
"enable_2fa",
"review_account_activity"
]
}
}安全性
签名验证
Trae 使用 HMAC-SHA256 对 Webhook 载荷进行签名。签名包含在 X-Trae-Signature-256 请求头中。
验证签名 (Node.js)
javascript
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
const receivedSignature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}
// Express.js 中间件示例
app.use('/webhooks/trae', express.raw({ type: 'application/json' }));
app.post('/webhooks/trae', (req, res) => {
const signature = req.headers['x-trae-signature-256'];
const payload = req.body;
const secret = process.env.WEBHOOK_SECRET;
if (!verifyWebhookSignature(payload, signature, secret)) {
return res.status(401).send('Unauthorized');
}
// 处理 Webhook 事件
const event = JSON.parse(payload);
console.log('Received event:', event.event);
res.status(200).send('OK');
});验证签名 (Python)
python
import hmac
import hashlib
import json
from flask import Flask, request, abort
app = Flask(__name__)
def verify_webhook_signature(payload, signature, secret):
expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
received_signature = signature.replace('sha256=', '')
return hmac.compare_digest(expected_signature, received_signature)
@app.route('/webhooks/trae', methods=['POST'])
def handle_webhook():
signature = request.headers.get('X-Trae-Signature-256')
payload = request.get_data()
secret = os.environ.get('WEBHOOK_SECRET')
if not verify_webhook_signature(payload, signature, secret):
abort(401)
# 处理 Webhook 事件
event = json.loads(payload)
print(f'Received event: {event["event"]}')
return 'OK', 200其他安全头
| 请求头 | 描述 |
|---|---|
X-Trae-Event | 事件类型 |
X-Trae-Delivery | 投递 ID |
X-Trae-Webhook-ID | Webhook ID |
X-Trae-Timestamp | 时间戳 |
User-Agent | Trae-Webhooks/1.0 |
重试策略
默认重试策略
- 最大重试次数: 3
- 退避策略: 指数退避
- 初始延迟: 1 秒
- 最大延迟: 60 秒
- 重试条件: HTTP 状态码 >= 500 或网络错误
自定义重试策略
json
{
"retry_policy": {
"max_attempts": 5,
"backoff_strategy": "exponential",
"initial_delay": 2000,
"max_delay": 300000,
"retry_on_status": [500, 502, 503, 504],
"retry_on_timeout": true
}
}退避策略
- linear: 线性增长 (delay = initial_delay * attempt)
- exponential: 指数增长 (delay = initial_delay * 2^(attempt-1))
- fixed: 固定延迟 (delay = initial_delay)
示例
创建和管理 Webhook
javascript
// 创建 Webhook
const createWebhook = async (webhookData) => {
const response = await fetch('/api/webhooks', {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(webhookData)
});
const webhook = await response.json();
if (response.ok) {
console.log('Webhook 创建成功:', webhook.webhook_id);
return webhook;
} else {
throw new Error(webhook.message);
}
};
// 使用示例
try {
const webhook = await createWebhook({
url: 'https://api.myapp.com/webhooks/trae',
events: [
'build.completed',
'build.failed',
'deployment.completed',
'deployment.failed'
],
name: 'CI/CD Notifications',
description: 'Receive build and deployment notifications',
secret: 'my-webhook-secret-key',
active: true,
project_id: 'proj_123',
headers: {
'X-API-Key': 'my-api-key'
},
timeout: 30,
retry_policy: {
max_attempts: 3,
backoff_strategy: 'exponential',
initial_delay: 1000,
max_delay: 60000
}
});
console.log('Webhook URL:', webhook.url);
console.log('订阅事件:', webhook.events);
} catch (error) {
console.error('创建 Webhook 失败:', error.message);
}处理 Webhook 事件
javascript
// Express.js Webhook 处理器
const express = require('express');
const crypto = require('crypto');
const app = express();
// 中间件:原始载荷解析
app.use('/webhooks/trae', express.raw({ type: 'application/json' }));
// Webhook 处理器
app.post('/webhooks/trae', (req, res) => {
try {
// 验证签名
const signature = req.headers['x-trae-signature-256'];
const payload = req.body;
const secret = process.env.WEBHOOK_SECRET;
if (!verifyWebhookSignature(payload, signature, secret)) {
console.error('Webhook 签名验证失败');
return res.status(401).send('Unauthorized');
}
// 解析事件
const event = JSON.parse(payload);
const eventType = event.event;
const eventData = event.data;
console.log(`收到 Webhook 事件: ${eventType}`);
// 根据事件类型处理
switch (eventType) {
case 'build.completed':
handleBuildCompleted(eventData);
break;
case 'build.failed':
handleBuildFailed(eventData);
break;
case 'deployment.completed':
handleDeploymentCompleted(eventData);
break;
case 'deployment.failed':
handleDeploymentFailed(eventData);
break;
case 'collaboration.invited':
handleCollaborationInvited(eventData);
break;
case 'security.alert':
handleSecurityAlert(eventData);
break;
default:
console.log(`未处理的事件类型: ${eventType}`);
}
// 返回成功响应
res.status(200).send('OK');
} catch (error) {
console.error('处理 Webhook 事件时出错:', error);
res.status(500).send('Internal Server Error');
}
});
// 事件处理函数
function handleBuildCompleted(data) {
console.log(`构建完成: ${data.build_id}`);
console.log(`项目: ${data.project_name}`);
console.log(`分支: ${data.branch}`);
console.log(`持续时间: ${data.duration}秒`);
// 发送通知到 Slack
sendSlackNotification({
text: `✅ 构建成功`,
attachments: [{
color: 'good',
fields: [
{ title: '项目', value: data.project_name, short: true },
{ title: '分支', value: data.branch, short: true },
{ title: '提交', value: data.commit_sha.substring(0, 7), short: true },
{ title: '持续时间', value: `${data.duration}秒`, short: true }
],
actions: [{
type: 'button',
text: '查看构建',
url: data.logs_url
}, {
type: 'button',
text: '预览部署',
url: data.deploy_preview_url
}]
}]
});
}
function handleBuildFailed(data) {
console.log(`构建失败: ${data.build_id}`);
console.log(`项目: ${data.project_name}`);
console.log(`错误: ${data.error.message}`);
// 发送通知到 Slack
sendSlackNotification({
text: `❌ 构建失败`,
attachments: [{
color: 'danger',
fields: [
{ title: '项目', value: data.project_name, short: true },
{ title: '分支', value: data.branch, short: true },
{ title: '提交', value: data.commit_sha.substring(0, 7), short: true },
{ title: '错误', value: data.error.message, short: false }
],
actions: [{
type: 'button',
text: '查看日志',
url: data.logs_url
}]
}]
});
}
function handleDeploymentCompleted(data) {
console.log(`部署完成: ${data.deployment_id}`);
console.log(`环境: ${data.environment}`);
console.log(`URL: ${data.url}`);
// 发送邮件通知
sendEmailNotification({
to: data.author.email,
subject: `部署成功 - ${data.project_name}`,
template: 'deployment-success',
data: {
project_name: data.project_name,
environment: data.environment,
url: data.url,
commit_message: data.commit_message,
author_name: data.author.name
}
});
}
function handleSecurityAlert(data) {
console.log(`安全警报: ${data.alert_type}`);
console.log(`严重程度: ${data.severity}`);
console.log(`用户: ${data.user.username}`);
// 立即通知安全团队
sendSecurityAlert({
alert_id: data.alert_id,
alert_type: data.alert_type,
severity: data.severity,
user: data.user,
details: data.details,
actions_taken: data.actions_taken
});
}
// 辅助函数
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
const receivedSignature = signature.replace('sha256=', '');
return crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex')
);
}
function sendSlackNotification(message) {
// 实现 Slack 通知逻辑
console.log('发送 Slack 通知:', message.text);
}
function sendEmailNotification(email) {
// 实现邮件通知逻辑
console.log('发送邮件通知:', email.subject);
}
function sendSecurityAlert(alert) {
// 实现安全警报逻辑
console.log('发送安全警报:', alert.alert_type);
}
app.listen(3000, () => {
console.log('Webhook 服务器运行在端口 3000');
});监控和统计
javascript
// 获取 Webhook 统计
const getWebhookStats = async (webhookId, period = 'day') => {
const response = await fetch(`/api/webhooks/${webhookId}/stats?period=${period}`, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
const stats = await response.json();
if (response.ok) {
return stats;
} else {
throw new Error(stats.message);
}
};
// 监控 Webhook 健康状态
const monitorWebhookHealth = async (webhookId) => {
try {
const stats = await getWebhookStats(webhookId);
const successRate = stats.overall_stats.success_rate;
const avgResponseTime = stats.overall_stats.average_response_time;
console.log(`Webhook ${webhookId} 健康状态:`);
console.log(`- 成功率: ${successRate}%`);
console.log(`- 平均响应时间: ${avgResponseTime}ms`);
// 健康状态检查
if (successRate < 95) {
console.warn('⚠️ 成功率低于 95%,需要检查');
// 获取最近的失败投递
const deliveries = await getWebhookDeliveries(webhookId, {
status: 'failed',
limit: 10
});
console.log('最近的失败投递:');
deliveries.deliveries.forEach(delivery => {
console.log(`- ${delivery.event_type}: ${delivery.error}`);
});
}
if (avgResponseTime > 5000) {
console.warn('⚠️ 平均响应时间超过 5 秒,可能存在性能问题');
}
return {
healthy: successRate >= 95 && avgResponseTime <= 5000,
successRate,
avgResponseTime
};
} catch (error) {
console.error('获取 Webhook 统计失败:', error.message);
return { healthy: false, error: error.message };
}
};
// 定期健康检查
setInterval(async () => {
const webhooks = await getWebhooks();
for (const webhook of webhooks.webhooks) {
if (webhook.active) {
const health = await monitorWebhookHealth(webhook.webhook_id);
if (!health.healthy) {
console.error(`Webhook ${webhook.name} 不健康:`, health);
// 发送警报
await sendAlert({
type: 'webhook_unhealthy',
webhook_id: webhook.webhook_id,
webhook_name: webhook.name,
details: health
});
}
}
}
}, 5 * 60 * 1000); // 每 5 分钟检查一次测试 Webhook
javascript
// 测试 Webhook
const testWebhook = async (webhookId, eventType = 'test.ping') => {
const response = await fetch(`/api/webhooks/${webhookId}/test`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
event_type: eventType,
payload: {
test: true,
timestamp: new Date().toISOString(),
message: 'This is a test webhook delivery'
}
})
});
const result = await response.json();
if (response.ok) {
console.log('Webhook 测试成功:');
console.log(`- 投递 ID: ${result.delivery_id}`);
console.log(`- 状态: ${result.status}`);
console.log(`- 响应码: ${result.response_code}`);
console.log(`- 响应时间: ${result.response_time}ms`);
return result;
} else {
throw new Error(result.message);
}
};
// 批量测试所有 Webhook
const testAllWebhooks = async () => {
try {
const webhooks = await getWebhooks({ active: true });
console.log(`测试 ${webhooks.webhooks.length} 个活跃的 Webhook...`);
for (const webhook of webhooks.webhooks) {
console.log(`\n测试 Webhook: ${webhook.name}`);
try {
const result = await testWebhook(webhook.webhook_id);
if (result.status === 'success') {
console.log('✅ 测试通过');
} else {
console.log('❌ 测试失败:', result.error);
}
} catch (error) {
console.log('❌ 测试出错:', error.message);
}
}
} catch (error) {
console.error('批量测试失败:', error.message);
}
};
// 使用示例
testAllWebhooks();