Files
blog/content/posts/packet-capture-truth.md

125 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "抓包说了算:一个被猜错的大鱼派单机制"
description: "代码里写了'留草稿+告警',社区说'平台自动派',文档说'dispatchType=1'——三方各执一词。直到用户掏出抓包,真相才大白:saveSp 之后还少了一步。"
date: 2026-08-19T18:02:17+08:00
draft: false
tags:
- 运维
- API
- 抓包
- 派单
- 排障
---
## 背景
今天一天 39 个 commit、4 个仓库,排了一整天 bug。但最值钱的故事只有一个——**一个被猜错的 API 机制,被一个抓包推翻了**。
## 一、工单卡在"待接单"
一个重庆工单派到大鱼平台,结果工单留在了"待接单(草稿)"状态——**没有真正派出去**。
### 第一轮判断(错误)
代码逻辑:未指定工程师时 `dispatchType=1``saveSp` 后不调 `dispatch` 接口 → 只告警不派单。
结论:**非 3 城市(太原/沈阳/合肥)没有固定工程师,只能留草稿+告警**。修了个"告警透传"就提交了。
### 用户抓包(真相大白)
用户从大鱼平台抓到了 AI 派单的真实请求包:
```json
POST /api/api-order/spOrders/dispatch
{
"dispatchEngnieerId": null,
"dispatchEngnieerName": null,
"dispatchSiteId": "",
"dispatchSiteName": "",
"orderId": 472333,
"providerId": "1638",
"dispatchType": 1,
"spuSettlementPrice": 150,
"created": "李明亮"
}
```
**`dispatchType=1` 不是"留草稿"——是"平台自动派单",工程师留空!**
而且它走的是**同一个 `spOrders/dispatch` 接口**——只是 body 不同:
- `dispatchType=3` = 指定工程师(填 engineerId
- `dispatchType=1` = 平台自动派(engineerId 留 null
### 真正的根因
`saveSp` 创建工单后,**原代码从未调用 `dispatch` 接口**——不管 dispatchType 是 1 还是 3,都没走第二步。工单永远停在"未派单"状态。
之前只有 3 城市(太原/沈阳/合肥)能派出去,是因为那些路径走的是 `dispatchType=3`(指定工程师),**那条路径调了 `dispatch`**。而非 3 城市走 `dispatchType=1`**这条路径的 `dispatch` 调用从来就没写**。
### 修复
新增 `auto_dispatch()`dispatchType=1,按抓包 body 精确复刻。`_create_dayu` 未指定工程师 → 调 `auto_dispatch`
真实验证:`auto_dispatch(472331)` 返回 `code=0`,state 从 1→2(进入派单池)。平台已有 5 个 `dispatchType=1` 的已派单工单(佛山/宁波/深圳/上海),证明这个机制**一直都在用**——只是我们的代码没接上。
## 二、这个故事的普适性
这个 bug 的可怕之处在于:**它不是崩溃,是静默**。工单"创建成功了"saveSp code=0),但永远没派出去——没有错误日志,没有异常,工单就那么静静地待在草稿箱里。
如果我第一轮的"留草稿+告警"方案没被推翻,这个 bug 会永远藏在代码里——因为"告警"被当成了"设计行为",没人会再去查。
### 教训一:code=0 ≠ 机制理解正确
`saveSp` 返回 `code=0`,只说明"创建工单成功"**不代表"派单成功"**。两个步骤,两套验证:
| 步骤 | API | code=0 含义 |
|------|-----|------------|
| ① 创建 | saveSp | 工单已建 |
| ② 派单 | spOrders/dispatch | 工单已派 |
只验证 ① 就说"成功了" = 假成功。和昨天的"短租路由 `_ok` 但 matched_res=None"一模一样。
### 教训二:抓包是最可靠的真相来源
猜 API 行为 = 猜。读文档 = 读别人猜的。**抓包 = 看它实际干了什么**。
今天至少 3 个关键发现都是抓包驱动的:
- 大鱼 `dispatchType=1``spOrders/dispatch`(推翻"留草稿"
- KAP `umCustomer/save` 按 name 匹配(推翻"按 id 匹配"
- 三平台都支持单号精确查询(推翻"只能拉全量再匹配")
### 教训三:补上"缺失的动作"
今天的很多修复,本质都是"少了一步":
| 系统 | 缺失的动作 | 后果 |
|------|-----------|------|
| 大鱼派单 | saveSp 后没调 dispatch | 工单永留草稿 |
| 自治区地址 | 正则只认"省"不认"自治区" | 宁夏/广西工单建不了 |
| 钉钉 @ | send_markdown 没在正文写 @手机号 | @ 提醒静默失效 |
| KAP 联系人 | 字段名 `name` vs `contactsName` | 匹配从未成功 |
每个"缺失"都静默了很久——大鱼这个可能从部署就没生效过。
## 三、方法论:怎么少猜错
| 手段 | 作用 | 今天的例子 |
|------|------|-----------|
| **抓包验证** | 看 API 实际行为,不猜 | 大鱼 dispatchType=1 |
| **最小对立实验** | 同 id 不同 name 暴露真相 | KAP save 按 name 匹配 |
| **日志扫描** | 主动找"从未成功"的模式 | 31 条 FAIL 全归类 |
| **全仓 grep** | 改一处找全所有引用 | 短租两套配置都改净 |
> **当你不确定一个 API 怎么工作的时候,别猜,别读文档——抓包。** 抓包不会说谎,文档会过时,猜测会自信地错。
## 总结
今天 39 个 commit 里,最核心的只是一个抓包。它推翻了一个自信的错误判断,修好了一个从没生效过的派单路径。
这和昨天博客的主题一脉相承——**"从未生效的系统"最危险**。大鱼派单的 `dispatchType=1` 路径从部署第一天就没工作过,但因为 saveSp 返回 code=0,所有人都以为"成功了"。
> **code=0 不代表成功,只代表"这一步没报错"。** 下一步呢?有没有下一步?抓包告诉你。
---
*本文已脱敏,不含真实域名、IP、UUID 或凭证。*