API 参考已发布
RAILWISE-OS Webhook 集成指南
RAILWISE-OS Webhook 事件推送机制的配置与使用说明,支持事件订阅、签名验证与重试策略
API 参考
RAILWISE-OS Webhook 集成指南
Section titled “RAILWISE-OS Webhook 集成指南”AI语义标签:
#Webhook#事件推送#实时通知#签名验证#系统集成#开发者指南
RAILWISE-OS Webhook 机制允许外部系统在特定事件发生时接收实时推送通知。通过 Webhook,您可以实现:
- 数据同步:监测数据写入时自动同步到第三方系统
- 状态通知:任务状态变更时通知企业微信/钉钉
- 异常告警:监测数据异常时触发外部告警系统
- 工作流触发:项目阶段变更时触发 CI/CD 或业务工作流
1.1 推送机制
Section titled “1.1 推送机制”┌─────────────────┐ 事件发生 ┌─────────────────┐│ RAILWISE-OS │ ───────────────> │ 您的服务器 ││ (事件源) │ HTTP POST │ (接收端) │└─────────────────┘ └─────────────────┘ │ │ │ 签名验证 + 重试机制 │ 处理事件 │ │ 返回 2xx │ <──────────────────────────────── │2. 配置 Webhook
Section titled “2. 配置 Webhook”2.1 创建 Webhook
Section titled “2.1 创建 Webhook”- 登录 RAILWISE-OS 管理后台
- 进入 系统设置 → 集成中心 → Webhook
- 点击“新建 Webhook”
- 填写配置信息:
| 配置项 | 说明 | 示例 |
|---|---|---|
| 名称 | Webhook 标识 | “企业微信通知” |
| URL | 接收推送的地址 | https://your-app.com/webhook/railwise |
| 事件类型 | 订阅的事件列表 | data.created, task.status_changed |
| 密钥 | 签名验证密钥(自动生成) | whsk_xxxxxxxxxxxxxxxx |
| 重试策略 | 失败重试配置 | 最多 3 次,间隔 5 秒 |
| IP 白名单 | 允许的源 IP(可选) | 123.45.67.89 |
2.2 Webhook 管理 API
Section titled “2.2 Webhook 管理 API”# 创建 Webhookcurl -X POST "https://api.os.railwise.cn/v3/webhooks" \ -H "X-API-Key: rwsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "name": "企业微信通知", "url": "https://your-app.com/webhook/railwise", "events": ["data.created", "data.abnormal", "task.status_changed"], "retry_policy": { "max_retries": 3, "retry_interval": 5 }, "active": true }'响应示例:
{ "code": 200, "data": { "id": "whk_abc123", "name": "企业微信通知", "url": "https://your-app.com/webhook/railwise", "secret": "whsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "events": ["data.created", "data.abnormal", "task.status_changed"], "active": true, "created_at": "2026-07-08T12:00:00Z" }}重要:
secret仅返回一次,请妥善保存用于签名验证。
2.3 更新与删除
Section titled “2.3 更新与删除”# 更新 Webhookcurl -X PUT "https://api.os.railwise.cn/v3/webhooks/whk_abc123" \ -H "X-API-Key: rwsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "events": ["data.created", "data.abnormal", "task.status_changed", "report.generated"] }'
# 删除 Webhookcurl -X DELETE "https://api.os.railwise.cn/v3/webhooks/whk_abc123" \ -H "X-API-Key: rwsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 测试 Webhook(发送测试事件)curl -X POST "https://api.os.railwise.cn/v3/webhooks/whk_abc123/test" \ -H "X-API-Key: rwsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"3. 事件类型
Section titled “3. 事件类型”3.1 数据事件
Section titled “3.1 数据事件”| 事件标识 | 说明 | 触发时机 |
|---|---|---|
data.created |
数据创建 | 监测数据写入成功 |
data.updated |
数据更新 | 监测数据修改 |
data.abnormal |
数据异常 | 监测数据触发异常规则 |
data.batch_completed |
批量写入完成 | 批量数据写入处理完成 |
3.2 任务事件
Section titled “3.2 任务事件”| 事件标识 | 说明 | 触发时机 |
|---|---|---|
task.created |
任务创建 | 新任务创建 |
task.assigned |
任务分配 | 任务分配给执行人 |
task.status_changed |
状态变更 | 任务状态发生变化 |
task.completed |
任务完成 | 任务标记为完成 |
task.overdue |
任务逾期 | 任务超过截止日期 |
3.3 项目事件
Section titled “3.3 项目事件”| 事件标识 | 说明 | 触发时机 |
|---|---|---|
project.created |
项目创建 | 新项目立项 |
project.status_changed |
项目状态变更 | 项目阶段变化 |
project.completed |
项目完成 | 项目归档 |
3.4 报告事件
Section titled “3.4 报告事件”| 事件标识 | 说明 | 触发时机 |
|---|---|---|
report.generated |
报告生成 | 报告生成完成 |
report.approved |
报告审批 | 报告通过审批 |
report.rejected |
报告驳回 | 报告被驳回 |
4. 推送 Payload
Section titled “4. 推送 Payload”4.1 通用 Payload 结构
Section titled “4.1 通用 Payload 结构”{ "event_id": "evt_abc123def456", "event_type": "data.created", "timestamp": "2026-07-08T12:00:00Z", "webhook_id": "whk_abc123", "data": { // 事件具体数据,见下文 }}4.2 data.created 事件
Section titled “4.2 data.created 事件”{ "event_id": "evt_abc123def456", "event_type": "data.created", "timestamp": "2026-07-08T12:00:00Z", "webhook_id": "whk_abc123", "data": { "project_id": "proj_abc123", "project_name": "宁波绕城高速管廊监测项目", "records": [ { "data_id": "data_001", "point_id": "point_k12_350_01", "point_name": "K12+350-1#", "sensor_type": "total_station", "measured_at": "2026-07-08T08:00:00+08:00", "values": { "x": 395123.456, "y": 2812345.678, "z": 15.234, "dx": 0.5, "dy": -0.3, "dz": 0.1 }, "status": "normal", "quality_flag": "valid" } ], "total_count": 1, "abnormal_count": 0 }}4.3 data.abnormal 事件
Section titled “4.3 data.abnormal 事件”{ "event_id": "evt_def456ghi789", "event_type": "data.abnormal", "timestamp": "2026-07-08T12:00:00Z", "webhook_id": "whk_abc123", "data": { "project_id": "proj_abc123", "project_name": "宁波绕城高速管廊监测项目", "alert_level": "warning", "records": [ { "data_id": "data_002", "point_id": "point_k12_350_02", "point_name": "K12+350-2#", "sensor_type": "total_station", "measured_at": "2026-07-08T08:00:00+08:00", "values": { "dx": 3.2, "dy": -2.8, "dz": 1.5 }, "status": "warning", "threshold": { "warning": 3.0, "alarm": 5.0 }, "reason": "X方向位移超过预警值 3.0 mm" } ] }}4.4 task.status_changed 事件
Section titled “4.4 task.status_changed 事件”{ "event_id": "evt_ghi789jkl012", "event_type": "task.status_changed", "timestamp": "2026-07-08T12:00:00Z", "webhook_id": "whk_abc123", "data": { "task_id": "task_001", "task_name": "3号线K12+350断面自动化监测", "project_id": "proj_abc123", "project_name": "宁波绕城高速管廊监测项目", "previous_status": "in_progress", "current_status": "completed", "changed_by": { "user_id": "user_003", "name": "李四", "phone": "139****5678" }, "changed_at": "2026-07-08T11:30:00Z", "remark": "监测数据已上传,无异常" }}5. 签名验证
Section titled “5. 签名验证”5.1 签名算法
Section titled “5.1 签名算法”RAILWISE-OS 使用 HMAC-SHA256 对推送内容进行签名,验证请求的合法性。
签名头:
X-Railwise-Signature: sha256=<hex_signature>X-Railwise-Timestamp: 1720440000X-Railwise-Event-ID: evt_abc123def4565.2 验证步骤
Section titled “5.2 验证步骤”- 从请求头获取
X-Railwise-Timestamp和X-Railwise-Signature - 检查时间戳是否在 5 分钟以内(防重放攻击)
- 构造签名原文:
timestamp + "." + request_body - 使用 Webhook Secret 计算 HMAC-SHA256
- 对比签名是否一致
5.3 验证代码示例
Section titled “5.3 验证代码示例”// TypeScript / Node.js 验证示例import * as crypto from 'crypto';
function verifyWebhookSignature( payload: string, signature: string, timestamp: string, secret: string): boolean { // 1. 检查时间戳(5分钟窗口) const now = Math.floor(Date.now() / 1000); const eventTime = parseInt(timestamp, 10); if (Math.abs(now - eventTime) > 300) { console.error('时间戳过期,可能存在重放攻击'); return false; }
// 2. 构造签名原文 const signedPayload = `${timestamp}.${payload}`;
// 3. 计算 HMAC-SHA256 const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex');
// 4. 安全比较签名 const providedSignature = signature.replace('sha256=', ''); return crypto.timingSafeEqual( Buffer.from(expectedSignature, 'hex'), Buffer.from(providedSignature, 'hex') );}
// Express 中间件示例import express from 'express';
const app = express();const WEBHOOK_SECRET = 'whsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
app.post('/webhook/railwise', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-railwise-signature'] as string; const timestamp = req.headers['x-railwise-timestamp'] as string; const payload = req.body.toString();
if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) { return res.status(401).json({ error: '签名验证失败' }); }
const event = JSON.parse(payload); console.log(`收到事件: ${event.event_type}`);
// 处理事件 handleWebhookEvent(event);
res.status(200).json({ received: true });});# Python / Flask 验证示例import hmacimport hashlibimport timefrom flask import Flask, request, jsonify
app = Flask(__name__)WEBHOOK_SECRET = b'whsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
@app.route('/webhook/railwise', methods=['POST'])def railwise_webhook(): signature = request.headers.get('X-Railwise-Signature', '').replace('sha256=', '') timestamp = request.headers.get('X-Railwise-Timestamp', '') payload = request.get_data(as_text=True)
# 1. 检查时间戳 now = int(time.time()) event_time = int(timestamp) if abs(now - event_time) > 300: return jsonify({'error': '时间戳过期'}), 401
# 2. 构造签名原文 signed_payload = f'{timestamp}.{payload}'.encode('utf-8')
# 3. 计算 HMAC-SHA256 expected_signature = hmac.new( WEBHOOK_SECRET, signed_payload, hashlib.sha256 ).hexdigest()
# 4. 安全比较 if not hmac.compare_digest(expected_signature, signature): return jsonify({'error': '签名验证失败'}), 401
event = request.get_json() print(f"收到事件: {event['event_type']}")
# 处理事件 handle_event(event)
return jsonify({'received': True}), 2006. 重试机制
Section titled “6. 重试机制”6.1 重试策略
Section titled “6.1 重试策略”| 策略 | 默认值 | 说明 |
|---|---|---|
| 最大重试次数 | 3 | 超过后标记为失败 |
| 重试间隔 | 5 秒 | 首次失败后等待时间 |
| 重试间隔递增 | 指数退避 | 5s → 25s → 125s |
| 超时时间 | 30 秒 | 单次请求超时 |
6.2 响应要求
Section titled “6.2 响应要求”您的服务器必须返回 HTTP 2xx 状态码 表示接收成功:
| 状态码 | 含义 | 处理 |
|---|---|---|
200 |
成功 | 不再重试 |
201 |
已创建 | 不再重试 |
204 |
无内容 | 不再重试 |
3xx |
重定向 | 跟随重定向,最多 3 次 |
4xx |
客户端错误 | 不再重试,记录失败 |
5xx |
服务器错误 | 按策略重试 |
| 超时 | 无响应 | 按策略重试 |
6.3 查看推送日志
Section titled “6.3 查看推送日志”# 获取 Webhook 推送日志curl -X GET "https://api.os.railwise.cn/v3/webhooks/whk_abc123/deliveries" \ -H "X-API-Key: rwsk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"响应示例:
{ "code": 200, "data": { "items": [ { "delivery_id": "del_001", "event_id": "evt_abc123def456", "event_type": "data.created", "status": "delivered", "http_status": 200, "delivered_at": "2026-07-08T12:00:05Z", "duration_ms": 120 }, { "delivery_id": "del_002", "event_id": "evt_def456ghi789", "event_type": "data.abnormal", "status": "failed", "http_status": 500, "error": "Internal Server Error", "retry_count": 3, "failed_at": "2026-07-08T12:05:00Z" } ] }}7. 最佳实践
Section titled “7. 最佳实践”7.1 安全性
Section titled “7.1 安全性”- 使用 HTTPS:Webhook URL 必须使用 HTTPS
- 验证签名:始终验证请求签名,防止伪造
- 检查时间戳:防止重放攻击
- IP 白名单:配置允许的源 IP 范围
7.2 可靠性
Section titled “7.2 可靠性”- 幂等处理:相同 event_id 的事件可能重复推送,需幂等处理
- 异步处理:收到事件后立即返回 200,后台异步处理
- 监控告警:监控 Webhook 推送成功率,低于 95% 时告警
7.3 性能
Section titled “7.3 性能”- 快速响应:处理逻辑应在 5 秒内完成,避免超时
- 批量处理:对于高频事件,考虑批量处理而非逐条处理
8. 相关文档
Section titled “8. 相关文档”文档版本: v3.2.0 | 最后更新: 2026-07-08 | API版本: v3
