首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >危废称重终端对接笔记:断网补传、字段映射与事件回调的三个坑

危废称重终端对接笔记:断网补传、字段映射与事件回调的三个坑

原创
作者头像
用户12864219
发布于 2026-11-07 08:37:21
发布于 2026-11-07 08:37:21
730
举报

做危废物联网对接,最难的部分通常落在现场那台称重终端上,而不是省平台接口文档本身。终端在磅房里,网络时有时无,操作员一天要过几十车,中间还要换人换班。接口文档写的是理想路径,现场跑的是另一条路。

这篇记三个真实踩过的坑,都是对接后一两个月才暴出来的东西:断网期间的数据怎么补、字段映射在哪一层做、事件回调被谁吃掉。

一、断网补传:本地队列比「重试三次」靠谱

绝大多数终端对接的第一版都是这样写的:HTTP 请求失败,重试 3 次,还失败就记日志丢弃。这个写法在办公室测试没问题,到了磅房一周就会丢数据,因为现场断网经常不是几秒,而是几个小时——工地临时断电、光缆被挖、运营商基站维护。

正确的结构是本地先落盘、再异步上传,上传成功才置位,不成功就留着等下一轮。

数据表的关键不是「有没有上传」,而是三个状态字段:

代码语言:sql
复制
CREATE TABLE weigh_record (
  record_id     TEXT PRIMARY KEY,   -- 端侧生成,全局唯一,见下节
  plate_no      TEXT,               -- 车牌
  gross_weight  REAL,               -- 毛重 kg
  tare_weight   REAL,               -- 皮重 kg
  net_weight    REAL,               -- 净重 kg
  weigh_time    TEXT,               -- 称重时刻 ISO8601 带时区
  sync_state    INTEGER DEFAULT 0,  -- 0待传 1已传 2平台已确认 3人工处理
  retry_count   INTEGER DEFAULT 0,
  last_error    TEXT,               -- 最后一次失败原因,别只存错误码
  created_at    TEXT
);

sync_state 这里要分成「已传」和「平台已确认」两级,这是补传逻辑能不能收敛的分水岭。只记「已传」的话,请求超时但你不知道平台收没收到,重传就可能重复入库;记到「平台已确认」,才敢把这条从待传队列里拿掉。

补传的调度也不用太聪明,一个简单规则就够:

  • 每 30 秒扫一次 sync_state = 0 且 retry_count < 5 的记录,按 weigh_time 升序批量提交,单批不超过 50 条;
  • 批次内按时间正序,避免平台侧做时序判断时出现「后称的先到」;
  • retry_count 到 5 之后不要继续死磕,转为 sync_state = 3 并在终端界面给一条显式提示,让人看得见。闷着不报的队列,最后一定变成「数据怎么少了一车」的扯皮。

补传还要注意一件事:不要让补传把实时数据挤掉。现场常见做法是一条队列走所有请求,断网两小时后恢复,几百条补传排在前面,新称的一车要等十几分钟才上传。按 weigh_time 判断新鲜度、实时记录优先插队,能避免这个问题。

二、字段映射:别在业务代码里写死平台口径

对接第二个坑是字段映射。第一版往往是这样:拿平台的接口文档,照着字段一个个 if 过去,代码里到处是 if plate is None: plate = driver_name 这类兜底。

问题在于,同一个概念在不同平台、不同版本里叫法不一样:

业务概念

省平台常见字段

企业自有系统常见字段

现场读卡器常见字段

车牌号

plateNo / carNumber

vehicle_no / plate

card_plate / plateStr

毛重

grossWeight

gross_wt

w1

皮重

tareWeight

tare_wt

w2

净重

netWeight

net_wt

w1 - w2(常需自己算)

称重时间

weighTime(毫秒或秒)

weigh_time(字符串)

timestamp(Unix 秒)

废物代码

wasteCode

waste_code

不出现,靠人工选

联单号

manifestNo

manifest_no

不出现

把这些差异写在业务逻辑里,改一次平台就要动一次代码,而且改不干净——总有一处漏掉,线上表现为某个字段偶尔为空,查起来要翻日志。

更稳的做法是单独一层映射配置,业务代码只认内部标准模型:

代码语言:python
复制
FIELD_MAP = {
    "plate_no":     ["plateNo", "carNumber", "vehicle_no", "plate"],
    "gross_weight": ["grossWeight", "gross_wt", "w1"],
    "tare_weight":  ["tareWeight", "tare_wt", "w2"],
    "weigh_time":   ["weighTime", "weigh_time", "timestamp"],
}

def pick(raw: dict, keys: list[str]):
    for k in keys:
        v = raw.get(k)
        if v not in (None, "", 0):
            return v
    return None

这个写法有两个必须注意的点,都是踩过才记住的:

一是 0 和空要分开判。 上面 v not in (None, "", 0) 里把 0 当空值,对重量字段是错的——皮重为 0 是合法值(空车过磅),不能因为它是 0 就去取下一个候选字段。重量类字段只判 None 和 "",数字类字段单独处理。

二是时间戳单位不统一。 毫秒和秒混用是最常见的低级错误,13 位当 10 位解析会得到一个 1970 年附近的时间,或者一个几万年后的时间。落到库里之前统一转成本地时间字符串并带上时区,不要在不同层反复转。

映射层还要有一个「命中率统计」。上线后跑一周,按字段统计 pick() 返回 None 的比例,哪个字段的空值率高,说明那个平台的字段名还没穷举完。这比等业务方来报「数据不对」快得多。

三、事件回调:幂等键用 recordId,不要用自增主键

第三个坑是回调。称重终端通常要接收两类事件:平台下发的指令(比如要求补录、要求重新上传凭证),以及平台对已上传数据的确认。

回调翻车主要出在两个地方。

第一是幂等。 平台的确认回调可能重复推送——网络抖动、平台侧重试、你这边响应慢导致对方认为失败。如果确认逻辑写的是「收到确认就把本地记录状态改掉」,重复推送通常无害;但如果写的是「收到确认就往统计表加一条」,重复推送就会把数量做多。

幂等的键不能用本地自增 id,必须用端侧生成的 record_id。生成方式建议是「设备编号 + 称重时刻 + 序号」,保证断网重连、数据库重建之后还能算出同一个值,而不是依赖 UUID 之外的状态:

代码语言:python
复制
def make_record_id(device_sn: str, weigh_time: datetime, seq: int) -> str:
    return f"{device_sn}-{weigh_time:%Y%m%d%H%M%S}-{seq:04d}"

第二是回调的验签与超时。 回调接口收到请求后应该先做两件事:验签、落一条原始报文。不要在校验通过之后才存原始报文,现场排查九成情况要看「对方到底发的是什么」,报文丢了就只能靠猜。

另外,回调处理必须快速返回。常见做法是接住请求、写入消息队列、立即返回成功,真正的处理异步做。如果在回调里同步查库、算净重、调另一个接口,一旦某个环节慢,平台侧超时重试就会带来重复推送——然后你又回到幂等那个问题上。

一个容易忽略的细节:回调地址如果是内网穿透或反向代理,务必确认原始请求头没有被改写。 验签通常依赖原始 body 和特定 header,中间件做了一次 JSON 重排(比如把 "a":1 变成 "a": 1),验签就会一直失败,而日志上看起来一切正常——请求到了、返回 200、就是验不过。

四、上线前值得做的三件小事

不用等出问题再补。

  1. 写一批脏数据跑一遍。 车牌带空格、重量为 0、时间戳是秒不是毫秒、废物代码是空字符串,这四种情况各造一条,看系统是报错还是静默吞掉。静默吞掉的最危险。
  2. 把「待传队列长度」做成可观测量。 不是日志,是能一眼看到的数字。队列持续大于 0 就说明补传没收敛,这是最早能发现的信号。
  3. 做一次完整的断网演练。 拔网线两小时,看恢复后数据齐不齐、顺序对不对、有没有重复。演练一次的收获,通常比读三遍接口文档多。

小结

断网补传的本质是把「一次请求」改成「一个有状态、可重放的队列」;字段映射的本质是把平台差异挡在一层配置里,不让它渗进业务代码;事件回调的本质是把「收到就算完成」改成「幂等 + 可追溯」。

这三件事都不复杂,但都需要在架构上留出位置。留了位置,后面接第三个、第四个平台时会轻松很多;没留位置,每接一个平台就是一次重写。


本文由河南白泽环保科技有限公司技术团队整理,内容为危废物联网称重终端对接的工程实践记录,不含具体项目数据与客户信息。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、断网补传:本地队列比「重试三次」靠谱
  • 二、字段映射:别在业务代码里写死平台口径
  • 三、事件回调:幂等键用 recordId,不要用自增主键
  • 四、上线前值得做的三件小事
  • 小结
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档