Files
chis_osi/docs/02-旧项目架构评估.md
T

83 lines
6.3 KiB
Markdown
Raw Normal View History

# 02 · 旧项目(chis_upload)架构评估
`chis_upload` 是通过**逆向 Chrome F12 网页接口**实现的 PHIS→CHIS 上传工具(Go 1.24)。
本文梳理它的分层与组件,区分「哪些复杂度是被网页逆向逼出来的、新项目应删除」与「哪些工程经验值得保留」。
---
## 1. 整体定位与数据流
旧项目本质是一个**数据搬运管道**:
```
PHIS(上游公卫系统) --拉取任务--> chis_upload --(模拟网页登录态)--> CHIS 网页后端
```
它对外暴露一组 HTTP API(`/api/health-record/save` 等),内部再以网页同款报文调用 CHIS。
另有 worker 模式:轮询 PHIS 拉任务、按 `dataType` 分流、调用自身 save API 完成投递。
---
## 2. 分层与目录职责(摘自其 AGENTS.md 与源码)
| 目录 | 职责 |
| --- | --- |
| `config/` | viper 读取 `config.yaml` |
| `util/` | SM2 加密、Redis、报告日志(reportlog)、apitrace、日志 |
| `chis/` | CHIS 调用核心:client/transport/auth/login + 各业务域 save/query + 归一化器/补齐器/身份链/完整度计算 |
| `model/` | 请求/响应结构体 |
| `handler/` | 对外 HTTP API 处理函数 |
| `middleware/` | Cookie 中间件(登录态注入) |
| `router/` | 路由注册(每个 save/query 都套 `authMW`) |
| `worker/` | phis_poll_worker、mock_task_worker、幂等存储、批次报告 |
`chis/` 目录尤其庞大(30+ 文件),是复杂度集中地。
---
## 3. 复杂度来源分析
### 3.1 由「网页逆向」逼出来的复杂度 —— 新项目应整体删除
| 旧项目机制 | 为什么存在 | OSI 下的命运 |
| --- | --- | --- |
| **SM2 加密**(`util/encrypt.go`:`EncryptSM2`/`GenerateLwD`/`GenerateQueryD`/`YearLlxKey`) | 网页登录与查询参数 `lw_d`/`d` 用 SM2 公钥加密,按年份还有动态字段名 `2026llx` | ❌ 删除。OSI 用 MD5 头签名 |
| **登录流程**(`chis/login.go`、`LoginWithRoleHint`、`identity_chain.go`) | 网页要先登录拿 Cookie,且要处理多角色选择 | ❌ 删除。OSI 无登录 |
| **Cookie/会话**(`middleware/cookie.go`、`chis/auth.go` `RedisCookieAuth`、`validate_cookie.go`、`util/redis.go` cookie 缓存、`cookie_ttl` 配置) | 维持网页登录态、跨请求复用、过期重登 | ❌ 删除。OSI 每请求现签,无状态 |
| **身份链反查**(`chis/identity_chain.go`:`idCard → empiId/phrId/...`) | 网页保存需要先把身份证换成内部主键链路 | ❌ 删除/大幅简化。OSI 直接用 `idCard`+`checkId`,`phrId` 由创建接口回传 |
| **Chrome 报文对齐**(`chrome_payload_compat_enable`、各 `*_payload_normalizer.go`、`health_check_enricher.go`) | 必须把字段补齐成 Chrome F12 抓到的同款形态,否则后端拒绝 | ⚠ 转化。不再"对齐网页",而改为"映射到文档契约"——见下 |
| **完整度服务端重算**(`health_record_complete_level.go` 37/33 项、`health_check_perfection.go` 70 项) | 逆向得知网页会算 completeLevel/perfection,客户端不可信任传入值,需本地重算 | ⚠ 待定。OSI 有显式 `isFillShhj`,完整度很可能由平台算;需联调确认后决定保留与否 |
| **网页拟态请求头**(`buildCHISCallHeaders`:`Origin`/`Referer`/`X-Requested-With`/`Host`) | 让请求看起来像浏览器发的 | ❌ 删除。OSI 是正式服务接口,无需伪装 |
| **apitrace + 多套快照**(`util/apitrace.go`、`phis_snapshot_*`,且注释标"兼容保留") | 逆向期排障留下的多套追踪 | 🔁 收敛为一套 report log |
> 量级判断:`chis/` 目录约 70%~80% 的代码是为「骗过网页 + 复刻网页隐藏算法」服务的。
> OSI 接口让这部分**整体失去存在意义**。
### 3.2 值得保留的工程经验 —— 新项目应继承
| 旧项目机制 | 价值 | 新项目去向 |
| --- | --- | --- |
| **分层清晰 + 面向初级维护者**(AGENTS.md:可读、不过度抽象、必要中文注释) | 团队约定,降低接手成本 | ✅ 继承这套协作规范 |
| **统一调用入口**(`chis/client.go` `Call(ctx, account, path, req, out)`:拼地址→注入头→传输→反序列化→记日志) | 单点收敛传输与可观测 | ✅ 演化为 OSI `client.Call(ctx, serviceId, body, out)` |
| **传输层与代理**(`transport.go`/`http_client.go`,SOCKS5 支持、超时控制、避免 typed-nil jar panic) | 内网穿透/超时是真实运维需求 | ✅ 几乎原样保留(去掉 cookiejar) |
| **投递流水线**(`worker/`:任务校验分流、**重试分类**、**幂等去重**、**熔断**、**批次报告**、跑完自动退出) | 这是搬运管道的可靠性核心,与接口形态无关 | ✅ 重点保留并升级 |
| **重试错误分类**(网络/5xx/429/网络型 401 可重试;参数/权限不可重试;退避 `2s*attempt`) | 来之不易的运维经验 | ✅ 保留,适配 OSI 返回码(`405` 超时可重试) |
| **report log + 降级**(Redis 优先、不可用降级写本地 JSONL;带 trace_id) | 可观测 + 不强依赖 Redis | ✅ 保留,Redis 改为完全可选 |
| **统一错误体**(`APIError{error_code,error_message,trace_id}`) | 上游稳定解析 | ✅ 保留 |
| **配置驱动 + Redis 启动失败不阻断** | 联调友好 | ✅ 保留 |
### 3.3 旧项目的待改进点(新项目顺手修正)
- **幂等键弱**:旧键 `account|idCard|dataType|sha1(saveBody)`,依赖报文哈希,报文微调即视为新任务。OSI 有天然的 `checkId`,应作为幂等主键。
- **任务源是 mock 文件**:`mock_task_worker` 读本地 JSON,真实 PHIS 拉取/状态回写一直 TODO(见其 `phase9_todo_open_items.md`)。新项目应直接把 PHIS 接入做实。
- **多套追踪并存**:apitrace / reportlog / snapshot 三套,注释里自承"兼容保留",应收敛为一套。
- **handler 里大量"从原始 JSON 多路径兜底提取字段"**(`fillEMPIAndPHRFromContext` 等),是历史请求体不规范的补丁。新项目以明确契约杜绝。
- **server 与 worker 杂糅在 `main.go`**(flag 极多)。新项目用子命令拆分。
---
## 4. 给新项目的迁移启示(一句话)
> 把 `chis/` 里"对付网页"的 70% 删掉,保留并强化 `worker/` 那套"可靠投递"的 30%,
> 再把删掉的部分替换成一个**薄 OSI 客户端**和一个**厚字段映射层**。