Files
medical-mall/pages/mall/delivery/doc/需求文档(现用)/接口规范.md
2026-03-17 11:06:26 +08:00

23 KiB
Raw Blame History

配送对接接口规范(模拟三通一达后台 / Mock 承运方 Server

本文档用于定义“模拟承运方后台服务Mock Server”的接口与行为供平台在未接入真实承运方前完成联调与测试。

本文定位:

  • 规定 Mock Server 与平台后端之间的交互Webhook 推送 + 控制面 API
  • 规定平台侧建议的统一事件模型(用于入库、时间线展示、监控告警)。

关联文档:

  • 配送模块需求文档.md:目标/范围/验收与必须的故障注入
  • 状态映射表.md状态码映射建议Mock event_code -> 平台 status_code
  • 前端字段清单.md:安卓/Web 时间线展示字段契约

包含两类接口:

  1. Mock Server -> 平台Webhook 事件推送(模拟承运方回调)
  2. 平台/测试工具 -> Mock Server控制面 API创建运单、追加事件、运行场景、触发推送、查询轨迹

统一约定

  • 时间格式ISO 8601示例"2026-02-05T10:30:00+08:00"
  • 所有接口请求/响应均为 JSONContent-Type: application/json
  • 写操作建议携带 request_id 用于幂等与排查
  • 所有第三方回调应保存 raw_payload 用于审计

补充说明(安卓端 & Web 端使用场景):

  • 本文主要规范 Mock Server 与平台后端的交互;安卓/Web 客户端不应直接调用 Mock Server。
  • Web 端联调时如需浏览器直连平台接口,应由平台网关配置 CORS仅测试环境白名单避免将 Mock Server 暴露给公网。

一、目标与约束

  • 目标:用可控数据模拟关键配送节点与异常场景,覆盖验签、幂等、乱序/重复、延迟等测试。
  • 约束:本规范服务于测试/预发布环境,不用于生产承运方直连。

二、核心数据模型(建议统一存储字段)

  • carrier承运方标识例如YUNDA、YTO、KDN
  • tracking_no:运单号
  • event_id第三方事件唯一ID用于去重
  • event_time事件时间ISO8601
  • event_code:第三方原始事件码(尽量不改写,用于审计与一致性对齐)
  • event_text:第三方原始事件文案(前端时间线默认展示)
  • status_code平台统一状态ORDER_PLACED, SHIPPED, IN_TRANSIT, OUT_FOR_DELIVERY, READY_FOR_PICKUP, DELIVERED, EXCEPTION, RETURNED
  • node_name:节点名称(中转站/网点/城市)
  • location:节点位置描述(城市/网点地址,注意隐私)
  • description:事件详细描述
  • evidence_urls:证据照片/签名链接数组
  • estimated_arrivalETA若承运方提供可选
  • raw_payload:原始第三方 JSON审计
  • last_synced_at:本地同步时间

三、接入模式

  • 平台接收 Mock Server 的 Webhook 推送(推荐)。
  • 平台亦可主动调用 Mock Server 查询轨迹(模拟轮询补偿)。

范围说明(避免误解):

  • 若要实现“电子面单/在线下单自动获取运单号”,需要对接第三方(快递公司直连或聚合平台)提供的下单/面单接口。
  • 该类“下单/面单”接口不属于本 Mock Server 接口规范范围;本文只覆盖轨迹事件的推送/查询与相关验签、幂等与字段口径。

四、接口定义(示例)

  1. Mock Server -> 平台事件推送Webhook
  • URL: POST /webhook/express/status
  • 描述: 承运方/聚合方主动推送运单事件(单条或批量事件)。平台应校验签名并返回 HTTP 200 表示成功接收。
  • HTTP 头部(建议):
    • Content-Type: application/json
    • X-Client-Id: 承运方或聚合方ID
    • X-Timestamp: 推送时间戳(防重放)
    • X-Signature: HMAC-SHA256(body + X-Timestamp) 使用双方共享 secret
  • 回调示例(单事件): { "tracking_no":"YD123456789", "carrier":"YUNDA", "event_id":"e_20260205_0001", "event_code":"TRANSIT", "event_text":"运输中", "event_time":"2026-02-05T14:32:00+08:00", "node_name":"北京分拨中心", "location":"北京市朝阳区XXX", "evidence_urls":[], "raw_payload":{/* 原始承运方 JSON */} }

处理要求:

  • 平台校验 X-SignatureX-Timestamp;若验签失败或时间差过大返回 4xx。若成功返回 HTTP 200。接收后异步完成映射与入库。
  • 幂等:基于 event_idtracking_no+event_code+event_time 去重。
  1. 平台 -> Mock Server轨迹主动拉取模拟轮询
  • URL: GET /mock/v1/track?tracking_no={tracking_no}&carrier={carrier}
  • 描述: 平台主动查询单运单轨迹,返回事件数组。
  • 响应示例: { "tracking_no":"YD123456789", "carrier":"YUNDA", "events":[ {"event_id":"e1","event_code":"PICKED","event_text":"已揽收","event_time":"2026-02-04T18:00:00+08:00","node_name":"门店揽收网点","location":"北京市顺义"}, {"event_id":"e2","event_code":"ARRIVAL","event_text":"运输中","event_time":"2026-02-05T14:32:00+08:00","node_name":"北京分拨中心","location":"北京市朝阳区"} ] }
  1. 平台:异常上报 API用户/客服触发,平台侧,不属于 Mock Server
  • URL: POST /api/v1/delivery/express/report-exception
  • 说明: 该接口为平台自身能力Mock Server 不强制实现。
  • 请求示例: { "tracking_no":"YD123456789", "reported_by":"user", "report_type":"damaged", "description":"包裹外包装破损,有压痕", "evidence_urls":["https://.../img1.jpg"] }
  • 平台可选地回传给真实承运方(若未来接入)并记录回传结果。
  1. 平台/测试工具 -> Mock Server控制面 API建议实现

4.1 配置回调目标

  • URL: POST /mock/v1/config
  • 描述: 设置 Mock Server 推送到平台的 Webhook 目标地址与验签参数。
  • 请求示例: { "target_webhook_url":"https://api.yourplatform.com/webhook/express/status", "client_id":"carrier_mock_yunda", "secret":"shared_secret", "default_carrier":"YUNDA" }

4.2 创建运单

  • URL: POST /mock/v1/waybills
  • 描述: 创建一个 mock 运单,可由调用方指定或由服务生成。
  • 请求示例: { "carrier":"YUNDA", "tracking_no":"YD123456789", "order_no":"202602050001" }
  • 响应示例: { "carrier":"YUNDA", "tracking_no":"YD123456789", "created_at":"2026-02-05T14:00:00+08:00" }

4.3 追加事件(不推送,仅入库)

  • URL: POST /mock/v1/waybills/{tracking_no}/events
  • 请求示例: { "event_id":"e_20260205_0002", "event_code":"TRANSIT", "event_text":"运输中", "event_time":"2026-02-05T14:32:00+08:00", "node_name":"北京分拨中心", "location":"北京市朝阳区", "evidence_urls":[] }

4.4 运行预置场景(生成一组事件并可选立即推送)

  • URL: POST /mock/v1/waybills/{tracking_no}/run-scenario
  • 请求示例: { "scenario":"standard_delivered", "push":true, "inject":{ "delay_ms":300, "duplicate":0, "out_of_order":false, "bad_signature":false, "timestamp_skew_seconds":0 } }

4.5 触发推送(把该运单事件推到平台)

  • URL: POST /mock/v1/waybills/{tracking_no}/push
  • 请求示例: { "mode":"all", "inject":{ "delay_ms":0, "duplicate":1, "out_of_order":true } }

4.6 查询运单轨迹Mock Server 自身查询接口)

  • URL: GET /mock/v1/waybills/{tracking_no}/track
  • 响应示例: { "carrier":"YUNDA", "tracking_no":"YD123456789", "events":[ {"event_id":"e1","event_code":"PICKED","event_text":"已揽收","event_time":"2026-02-04T18:00:00+08:00"} ] }

4.7 健康检查

  • URL: GET /mock/v1/health
  • 响应示例: {"status":"ok"}

五、字段映射与状态对照(示例)

  • 平台统一状态 OUT_FOR_DELIVERY 映射关系示例:
    • 韵达:承运方 派送中 -> 平台 OUT_FOR_DELIVERY
    • 聚合:原始 deliver -> 平台 OUT_FOR_DELIVERY

状态一致性策略(尽量保持平台与第三方一致):

  • 一致性定义:平台保存的 event_code/event_textraw_payload 应与第三方可查询到的轨迹语义一致;平台对外展示的 status_code 必须由映射表确定性生成(同一承运方同一 event_code 在同一版本映射下得到同一 status_code)。
  • 字段保真:event_code/event_text 仅做透传与脱敏展示,不建议“为了统一文案”而改写原文;统一展示口径使用 status_code 的标签/颜色/筛选实现。
  • 映射表治理:映射表变更需要版本化(例如 mapping_version)并走发布流程;避免在生产环境频繁调整导致历史轨迹“同码不同态”。如必须调整,建议补充回放/回填策略以保证历史一致。
  • 回查纠偏(可选增强):平台定期或按需对“关键单/争议单”触发第三方轨迹回查;若发现缺失事件则补采入库;若发现语义冲突,优先保留原始事件并追加“平台侧纠偏事件/备注”,避免静默覆盖造成审计对不上。

六、验签与安全

  • 建议使用 HMAC-SHA256 签名,签名字段为 body + X-Timestamp,服务端使用共享 secret 校验。
  • 防重放:校验 X-Timestamp 与当前时间差(例如 < 5 分钟),并保存最近 N 个 X-Signatureevent_id 用于去重。

七、幂等与重试策略

  • webhook承运方可能重试多次平台必须基于 event_id 或 (tracking_no+event_code+event_time) 去重。
  • 主动调用承运方接口失败时采用指数退避重试;关键操作(打单)建议入队异步重试并人工告警。

入库层(幂等去重、乱序处理)建议:

  • 幂等目标:同一条事件无论推送/重试多少次,最终数据库只保留一条(或同一条被安全更新),避免重复入库造成时间线膨胀。
  • 幂等键优先级:
    • 优先使用第三方提供的 event_id
    • 若缺少 event_id,使用兜底组合键:tracking_no + event_code + event_time(必要时可补充 node_name/location 以降低碰撞)。
  • 数据库约束:建议在事件表上建立唯一约束(例如 carrier + tracking_no + event_idtracking_no + dedupe_key),写入采用 Upsert/Insert-Ignore应用层无需“先查再写”来保证并发安全。
  • 乱序处理:允许事件乱序写入(以免晚到的历史节点被丢弃);查询展示时按 event_time 排序生成时间线。
  • 状态不回退(平台侧可选规则):当先收到终态(如 DELIVERED)后又收到更早时间的在途事件时,不应将订单状态从终态回退;可采用“以最新 event_time 事件计算 current_status”或“按状态流转等级仅允许前进”的策略。

八、展示与 UI 要求(与前端对接点)

  • 时间线按 event_time 展示,标注 carrier 来源与 last_synced_at
  • 节点可展开查看 descriptionnode_namelocationevidence_urls(签收照片/回单)。若无证据则隐藏预览。
  • 提供“查看第三方原文”链接,展示 raw_payload(仅客服/运维可见)。

平台对客户端返回建议(安卓/Web

  • 客户端请求应面向平台统一接口(例如:GET /api/v1/delivery/express/track?order_no=...),由平台返回统一的 status_history
  • 响应中建议包含:carriertracking_nostatusstatus_historylast_synced_at,以及可选的 eta
  • raw_payload 不建议下发给普通用户端;仅在 Web 客服/运维界面按权限下发并记录审计。

九、监控与告警

  • 指标webhook 接收成功率、平均同步时延、同步失败率、超过阈值未更新的运单数。
  • 告警:承运方 5xx 增加、webhook 验签失败率异常、单运单长时间无更新。

十、示例 cURLWebhook 验证场景模拟)

curl -X POST https://api.yourplatform.com/webhook/express/status \
  -H "Content-Type: application/json" \
  -H "X-Client-Id: carrier_yunda" \
  -H "X-Timestamp: 2026-02-05T14:32:00+08:00" \
  -H "X-Signature: <hmac-signature>" \
  -d '{"tracking_no":"YD123456789","event_id":"e_20260205_0001","event_code":"TRANSIT","event_time":"2026-02-05T14:32:00+08:00","event_text":"运输中"}'

十一、日志与保留策略

  • 建议保留 raw_payload 与入库审计日志至少 30 天以便纠纷处理审计记录包括接收时间、IP、头部信息与处理结果。

十二、兼容与扩展建议

  • 建议实现承运商 Adapter 层:承运方差异在 Adapter 层转换为统一模型,便于后续扩展新承运方或替换聚合方。
  • 若需签收照片或更高粒度信息,应优先与承运方签订企业级合同或直连,并在 UI 端明确注明凭证来源。

十二点一、平台后端适配架构(推荐实现方式)

目标:当不同第三方(直连承运方/聚合平台API 结构、鉴权方式、事件码不同的时候,平台侧不修改核心业务与数据库结构即可接入。

核心原则:

  • 统一领域模型入库:第三方差异在入库前完成映射;数据库保存统一事件字段 + raw_payload
  • Adapter 可插拔:每家第三方实现一个 Adapter验签/解析/查询/映射),核心服务只处理统一模型。
  • 接入入口两条线Webhook推送与 Poller轮询补偿最终都走同一条 EventIngestService

模块划分(建议):

  • WebhookController:接收回调、路由到对应 Adapter、快速返回 200业务异步处理
  • CarrierAdapter(每家一个):验签、解析、字段映射、状态映射、(可选)轨迹查询。
  • AdapterRegistry/Router:按 carrierX-Client-Id 选择 Adapter支持灰度与多配置
  • EventIngestService:幂等去重、乱序处理策略、统一入库、写审计日志。
  • TrackQueryService:给安卓/Web 提供统一查询接口(只读),不透出第三方差异。
  • PollerJob:定时对“长时间无更新”的运单做轮询补偿(可按承运方频率配置)。

幂等与乱序建议(平台侧):

  • 幂等键优先级:event_id(优先) > tracking_no + event_code + event_time(兜底)。
  • 入库:允许乱序写入;查询展示时按 event_time 排序。
  • 兼容缺字段:缺少 event_id 时必须使用兜底组合键;缺少 location/node_name 时 UI 降级仅展示 event_text

架构图Mermaid

flowchart LR
  subgraph Clients[客户端]
    A[安卓 App] -->|GET 物流时间线| PAPI[平台 API]
    W[Web/H5/PC] -->|GET 物流时间线| PAPI
  end

  subgraph Platform[平台后端]
    PAPI --> TQS[TrackQueryService\n统一查询]
    TQS --> DB[(Logistics DB\nWaybill + TrackingEvent)]

    WH[WebhookController\n接收回调] --> REG[AdapterRegistry/Router\n按carrier或X-Client-Id路由]
    REG --> AD1[YUNDA Adapter]
    REG --> AD2[YTO Adapter]
    REG --> AD3[Aggregator Adapter\n(快递鸟/快递100)]

    AD1 --> ING[EventIngestService\n幂等/映射/入库]
    AD2 --> ING
    AD3 --> ING
    ING --> DB

    PJ[PollerJob\n轮询补偿] --> REG
    PJ -->|queryTrack| AD1
    PJ -->|queryTrack| AD2
    PJ -->|queryTrack| AD3
  end

  subgraph ThirdParty[第三方/Mock]
    MS[Mock Server 或真实承运方/聚合] -->|Webhook 推送| WH
  end

回调时序图Webhook 推送 -> 入库 -> 客户端展示)

sequenceDiagram
  participant TP as Mock/第三方
  participant WH as WebhookController
  participant REG as AdapterRegistry
  participant AD as CarrierAdapter
  participant ING as EventIngestService
  participant DB as LogisticsDB
  participant API as 平台查询API
  participant APP as 安卓/Web

  TP->>WH: POST /webhook/express/status (headers + body)
  WH->>REG: resolveAdapter(carrier/X-Client-Id)
  REG->>AD: getAdapter()
  WH->>AD: verify + parseWebhook(rawBody)
  AD-->>WH: NormalizedEvent[]
  WH-->>TP: 200 OK (快速返回)
  WH->>ING: ingest(NormalizedEvent[])
  ING->>DB: upsert events (幂等去重)

  APP->>API: GET /api/v1/delivery/express/track?order_no=...
  API->>DB: query events (order_no/tracking_no)
  DB-->>API: events ordered by event_time
  API-->>APP: timeLine(status_history + last_synced_at)

备注Mermaid 图在不支持的 Markdown 渲染器中会降级为代码块,不影响内容阅读。

十三、附录:不同第三方 API 形态示例(用于理解差异)

说明:以下为“常见形态示例”,用于帮助团队理解不同第三方接口在鉴权、字段与能力上的差异。

  • 不保证与任一承运方/聚合平台的官方文档 100% 一致;对接时必须以官方文档、沙箱与实际回文为准。
  • 推荐做法:在平台侧实现 Adapter/Mapper把第三方差异映射为本文定义的统一事件模型再入库。

13.1 聚合平台常见形态如快递100/快递鸟类)

典型能力:

  • 轨迹查询 API传入 company_code + tracking_no(有些场景需要收件人手机号后四位)
  • 订阅/推送:先订阅,后续以 Webhook 回调推送事件
  • 鉴权:常见 appKey + signMD5/HMAC或 Token

示例:轨迹查询(示例)

POST https://api.aggregator.example.com/v1/track/query
Content-Type: application/json

{
  "company_code": "yunda",
  "tracking_no": "430123456789",
  "phone_last4": "8000",
  "nonce": "n_123",
  "timestamp": 1738735200,
  "sign": "md5_or_hmac_signature"
}

示例响应(示例)

{
  "success": true,
  "tracking_no": "430123456789",
  "company_code": "yunda",
  "state": "in_transit",
  "events": [
    { "time": "2026-02-05T10:12:00+08:00", "context": "已揽收", "location": "深圳市" },
    { "time": "2026-02-05T22:01:00+08:00", "context": "到达广州分拨中心", "location": "广州市" }
  ]
}

差异点:

  • state / status 枚举不统一;事件字段可能是 context/desctime/timestamp
  • 不同快递公司可能要求手机号参与查询或订阅验证。

13.2 承运方直连常见形态(企业接口)

典型能力:

  • 轨迹查询、签收回单POD查询可能拆成多个接口
  • 鉴权更严格HMAC、证书、IP 白名单或 OAuth2

示例:轨迹查询(示例)

POST https://open.carrier.example.com/v2/route/query
Content-Type: application/json
X-Client-Id: your_client_id
X-Timestamp: 2026-02-05T10:30:00+08:00
X-Signature: hmac_sha256(body + timestamp)

{
  "tracking_no": "SF1234567890",
  "include_pod": true
}

示例响应(示例)

{
  "tracking_no": "SF1234567890",
  "routes": [
    { "code": "PICKED", "desc": "已揽收", "time": "2026-02-05T09:10:00+08:00", "station": "深圳XX营业点" },
    { "code": "TRANSIT", "desc": "运输中", "time": "2026-02-05T21:45:00+08:00", "station": "广州分拨中心" }
  ],
  "pod": { "signed": false, "photo_url": null }
}

差异点:

  • 字段更细网点编码、操作员等但不统一POD 能力通常受权限/合同影响。

13.3 Webhook 推送常见形态(订阅后回调)

典型能力:

  • 订阅后由第三方主动推送轨迹事件到平台
  • 具备重试机制,因此平台必须做幂等去重、乱序处理

示例:回调事件(示例,字段名因第三方而异)

{
  "tracking_no": "430123456789",
  "carrier": "YUNDA",
  "event_id": "evt_0001",
  "event_time": "2026-02-05T22:01:00+08:00",
  "event_text": "到达广州分拨中心",
  "location": "广州市",
  "extra": { "pod_photo": null }
}

接入建议:

  • 无论第三方字段如何变化,平台入库前统一映射到本文“核心数据模型”,并保留 raw_payload
  • 平台用 event_id(优先)或组合键(tracking_no+event_code+event_time)实现幂等。

13.4 圆通YTO物流轨迹查询接口官方文档摘要

文档入口:

定位:该文档描述“根据圆通运单号查询物流轨迹”的接口形态,典型属于“平台主动查询(轮询)”模式。

关键交互要点(按官方文档整理,具体以控制台配置与最新文档为准):

  • 传输HTTPSPOST。
  • 报文结构:请求体包含 timestampparamformatsign
  • param:以 JSON/XML 字符串承载业务参数;轨迹查询场景下包含圆通运单号字段(示例为 NUMBER,一次查询一个单号)。

签名规则(按文档描述抽象):

  • 参与签名的明文:param + method + v(其中 methodv 来自控制台为该接口生成的配置)。
  • 将上述明文与客户密钥(secret)拼接后做 MD5再对 MD5 的字节结果进行 Base64 编码,得到 sign
  • 伪公式:sign = base64(md5((param + method + v) + secret))

响应字段(按文档列举的 JSON 返回字段抽象):

  • 运单号:waybill_No
  • 走件时间:upload_Timeyyyy-MM-dd HH:mm:ss
  • 物流状态码:infoContent(示例枚举包括 GOT/ARRIVAL/DEPARTURE/SENT_SCAN/SIGNED 等)
  • 物流信息文案:processInfo
  • 城市/区县:citydistrict(可选)
  • 重量:weight(可选)

平台侧映射建议(把第三方差异收敛到统一模型):

  • 时间:upload_Time -> 平台 event_time
  • 文案:processInfo -> 平台 event_text(可另存 description
  • 状态:infoContent -> 平台 event_code(保留原码),再映射到平台统一 status_code(见 状态映射表.md

infoContent 到平台统一 status_code 的建议映射(示例):

  • GOT已揽收-> IN_TRANSIT
  • ARRIVAL已收入/到达)-> IN_TRANSIT中转/到达节点统一视为运输中)
  • DEPARTURE已发出/离开节点)-> IN_TRANSIT
  • SENT_SCAN派件-> OUT_FOR_DELIVERY
  • INBOUND自提柜入柜-> IN_TRANSIT或按业务定义为 OUT_FOR_DELIVERY
  • SIGNED签收成功-> DELIVERED
  • FAILED签收失败-> EXCEPTION
  • TMS_RETURN退回-> RETURNED

落库建议:

  • 将圆通原始返回(整个数组或单条对象)保存到 raw_payload,便于客服/运维对照圆通官网。
  • 幂等去重:若第三方无稳定 event_id,可用组合键 tracking_no + infoContent + upload_Time 生成 dedupe_key

13.5 韵达YUNDA开放平台官方文档入口与调研清单

文档入口:

说明:韵达开放平台文档页面存在较多交互式内容(需登录/控制台配置后才能看到每个接口的 method/v/测试地址 等关键信息)。因此本节先固化“对接时必须确认的要点清单”,避免对接过程中遗漏。

从官方文档导航可见的能力分类(用于判断覆盖范围):

  • API 鉴权说明
  • 电子面单、散件下单
  • 物流轨迹
  • 售后服务、国际件、基础服务等

韵达轨迹对接需要在控制台确认/落盘的信息(建议形成《承运方接入配置表》):

  • 鉴权方式签名算法HMAC/MD5 等)、参与签名字段、编码/排序规则、是否包含时间戳与 nonce。
  • 接口要素:轨迹查询接口 URL、methodv(如平台/第三方采用“method+version+param”体系
  • 订阅/回调能力:是否支持轨迹订阅与回调推送、回调重试策略、回调验签字段。
  • 返回字段:事件时间字段、事件码/状态字段、事件文案字段、地点字段(城市/网点)与可选 POD 能力。

平台侧落地方式保持不变:

  • 无论韵达返回结构如何,统一通过 Adapter 映射为平台 TrackingEvent 领域模型入库,并保留 raw_payload

Mock 控制面通用错误码(示例)

  • 40001: invalid_parameter
  • 40002: missing_required_field
  • 40901: duplicate_request
  • 50001: internal_error

可选增强(非本期必需):

  • 生成 OpenAPI 文档(控制面 API + Webhook 示例)
  • 补齐“字段必填矩阵/容错矩阵”(配合 drop_fields 故障注入)