5.4 KiB
5.4 KiB
概述
- 目标: 让快递合作方(例如韵达)能安全、可靠地向系统的
/webhook/express/status发送回调,用于运单状态同步与推送触发。 - 范围: 包含鉴权/验签约定、幂等策略、测试样例、部署与运维建议。
接入概览
- Endpoint:
https://<your-domain>/webhook/express/status - 协议: HTTPS(TLS 必需)
- 数据格式:
application/json,body 为第三方原始回调 JSON。
鉴权与验签
- 方式: 每个合作方分配一份 HMAC secret(UTF-8 文本),服务端按
client_id查秘钥(建议把client_id放在请求头X-Client-Id)。 - 签名头:
X-Timestamp(UTC 秒)与X-Signature(hex 小写)。 - 签名算法: HMAC-SHA256(secret, rawBodyText + timestamp) → hex。
- 时窗: 接收端按 ±300 秒(可配置)判定时间窗,超时拒绝(防重放)。
- 严格模式:
WEBHOOK_REJECT_INVALID_SIGNATURE=true时签名不合将直接 401(上线初期可先设 false,观测后切为 true)。
幂等与去重
- 推荐字段: 合作方可在 body 中提供
dedupe_key(优先使用);若无,服务端基于稳定字段计算哈希(建议用tracking_no|carrier|event_time|event_code组合)。 - 数据库约束:
platform_express_tracking_events应有唯一约束(waybill_id, dedupe_key),重复回调不再写入事件表。 - 返回语义: 对重复回调可返回 200 并在 body 标注
duplicate: true,以便合作方不再重试。
请求/响应与重试策略
- 接收端快速 ACK: 推荐返回 HTTP 202 Accepted(或 200)表示“已入队/接收”,不代表处理完成。
- 错误返回: 4xx 表示请求问题(签名/格式),5xx 表示服务端异常(合作方可按重试策略重试)。
- 建议重试规则(对方遵守): 3–5 次,指数退避(例如 1m, 2m, 4m, ...),总重试时长不超过 1 小时。
示例:签名与发送(bash)
TS=$(date -u +%s)
BODY='{"tracking_no":"YT123","event_code":"DELIVERED","event_time":"2026-03-12T10:00:00Z"}'
SECRET='YOUR_PARTNER_SECRET'
SIG=$(printf '%s%s' "$BODY" "$TS" | openssl dgst -sha256 -hmac "$SECRET" -binary | xxd -p -c 256)
curl -v -X POST https://your-domain/webhook/express/status \
-H 'Content-Type: application/json' \
-H "X-Timestamp: $TS" \
-H "X-Signature: $SIG" \
-H "X-Client-Id: partner-yd" \
-d "$BODY"
示例:PowerShell(Windows)
$ts = [int][double]::Parse((Get-Date).ToUniversalTime().Subtract([datetime]'1970-01-01').TotalSeconds)
$body = '{"tracking_no":"YT123","event_code":"DELIVERED","event_time":"2026-03-12T10:00:00Z"}'
$secret = 'YOUR_PARTNER_SECRET'
$hmac = New-Object System.Security.Cryptography.HMACSHA256([Text.Encoding]::UTF8.GetBytes($secret))
$hash = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($body + $ts))
$sig = ($hash | ForEach-Object { $_.ToString("x2") }) -join ''
Invoke-RestMethod -Uri 'https://your-domain/webhook/express/status' -Method Post -Body $body -ContentType 'application/json' -Headers @{ 'X-Timestamp'=$ts; 'X-Signature'=$sig; 'X-Client-Id'='partner-yd' }
测试与沙箱
- 临时隧道: 联调期可使用
ngrok或cloudflared将本地服务映射到公网供合作方发送测试回调。 - 测试密钥: 为每个合作方发放
test_secret与prod_secret,并在系统中分离管理。 - 回放工具: 提供一个简单
test-send.js(仓库已有)并在 README 中示例化如何运行。
部署与网关建议
- 域名与 TLS: 使用
webhook.<your-domain>,证书推荐用 Let's Encrypt 自动续期。 - 反向代理 / 网关: 推荐放在 Nginx / Kong / Cloud Load Balancer 前做:
- TLS 终端、IP 白名单、速率限制(rate-limiting)、日志落盘与审计。
- 如使用 Kong,可在网关做
key-auth或 IP 白名单做第一道防护。
- WAF/防护: 对外公开时开启基础 WAF(过滤常见攻击)与 DDOS 保护。
监控与告警
- 关键 Metric: 接收量、验签失败率、重复率(duplicate percent)、处理延时、no-targets 率。
- 告警阈值: 验签失败率 >1% 或 no-targets 突增 触发 PagerDuty/邮件告警。
上线流程(最小安全步骤)
- 在测试环境配置 partner test_secret 与
X-Client-Id,提供示例脚本。 - 使用
ngrok联调,通过 2–3 次真实回调验证dedupe_key、waybill 匹配和入队。 - 把 partner 的 prod_secret 写入生产密钥存储(避免明文在 repo)。
- 在生产网关启用 IP 白名单或 key-auth,并在低流量窗口把
WEBHOOK_REJECT_INVALID_SIGNATURE改为true。
常见问题与排查
- 验签失败: 检查是否对方用了 stringify 后的 body 或时间戳单位不一致(秒 vs 毫秒);建议双方按示例脚本校验。
- 重复回调仍写入: 检查
dedupe_key的字段组合与 DB 唯一约束(waybill_id,dedupe_key)是否生效。 - no-targets: 确保
push_devices已按merchant_id或user_id正确写入(见GET /api/v1/push/devices验证)。
联系人与上游联调清单
- 提供方需给出: 回调样例(真实 JSON)、回调频率预估、回调 IP 段、是否支持
dedupe_key字段、联系人邮箱/电话。 - 我方需要提供:
test_secret、测试域名、示例脚本、接入说明(本文件)。
作者:自动生成;可根据合作方反馈补充示例与节流策略。