Files
medical-mall/pages/mall/delivery/webhook-server/PARTNER_ONBOARDING.md
2026-03-12 18:05:32 +08:00

5.4 KiB
Raw Blame History

概述

  • 目标: 让快递合作方(例如韵达)能安全、可靠地向系统的 /webhook/express/status 发送回调,用于运单状态同步与推送触发。
  • 范围: 包含鉴权/验签约定、幂等策略、测试样例、部署与运维建议。

接入概览

  • Endpoint: https://<your-domain>/webhook/express/status
  • 协议: HTTPSTLS 必需)
  • 数据格式: application/jsonbody 为第三方原始回调 JSON。

鉴权与验签

  • 方式: 每个合作方分配一份 HMAC secretUTF-8 文本),服务端按 client_id 查秘钥(建议把 client_id 放在请求头 X-Client-Id)。
  • 签名头: X-TimestampUTC 秒)与 X-Signaturehex 小写)。
  • 签名算法: 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 表示服务端异常(合作方可按重试策略重试)。
  • 建议重试规则(对方遵守): 35 次,指数退避(例如 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"

示例PowerShellWindows

$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' }

测试与沙箱

  • 临时隧道: 联调期可使用 ngrokcloudflared 将本地服务映射到公网供合作方发送测试回调。
  • 测试密钥: 为每个合作方发放 test_secretprod_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/邮件告警。

上线流程(最小安全步骤)

  1. 在测试环境配置 partner test_secret 与 X-Client-Id,提供示例脚本。
  2. 使用 ngrok 联调,通过 23 次真实回调验证 dedupe_key、waybill 匹配和入队。
  3. 把 partner 的 prod_secret 写入生产密钥存储(避免明文在 repo
  4. 在生产网关启用 IP 白名单或 key-auth并在低流量窗口把 WEBHOOK_REJECT_INVALID_SIGNATURE 改为 true

常见问题与排查

  • 验签失败: 检查是否对方用了 stringify 后的 body 或时间戳单位不一致(秒 vs 毫秒);建议双方按示例脚本校验。
  • 重复回调仍写入: 检查 dedupe_key 的字段组合与 DB 唯一约束 (waybill_id,dedupe_key) 是否生效。
  • no-targets: 确保 push_devices 已按 merchant_iduser_id 正确写入(见 GET /api/v1/push/devices 验证)。

联系人与上游联调清单

  • 提供方需给出: 回调样例(真实 JSON、回调频率预估、回调 IP 段、是否支持 dedupe_key 字段、联系人邮箱/电话。
  • 我方需要提供: test_secret、测试域名、示例脚本、接入说明(本文件)。

作者:自动生成;可根据合作方反馈补充示例与节流策略。