Files
chisup/docs/04-architecture.md
T
2026-07-04 23:30:53 +08:00

10 KiB

架构设计

本文讲系统结构、职责划分、数据模型、技术难点和开发顺序。具体技术选型见 技术栈。

一、系统结构

第三方系统
  |
  | HTTPS JSON
  v
Flask API / middleware
  |
  | create_app 注册 blueprint / middleware / config
  |
  | 参数校验、鉴权、幂等
  v
Application service
  |
  | 查询编排 / 上报编排 / 标准业务模型
  v
Mapper / transformer
  |
  | CHIS 保存请求模型
  v
CHIS client + auth manager
  |
  | cookies / session cache / optional CHIS_PROXY
  v
Redis
  |
  v
基卫 CHIS *.jsonRequest / 登录接口

API / service / CHIS client
  |
  +--> logs/      # 每天一个综合运行日志,保留 1 年
  |
  +--> archives/  # 每个 API 请求一个完整原始归档 JSON,不脱敏

二、职责划分

Flask application factory

  • app/__init__.py 暴露 create_app(config_object=None)。
  • 在 factory 内加载配置、注册 blueprint、注册 middleware / error handler。
  • 不在模块导入时读取真实 CHIS 凭证、连接 Redis 或发起外部请求。
  • 测试通过 factory 注入测试配置和 fake / mock 组件。

API / view

  • 接收第三方请求。
  • 完成第三方鉴权、trace_id、基础参数校验。
  • 调用 application service。
  • 返回统一响应。
  • 不写 CHIS 字段映射和登录细节。

middleware

  • 可以负责第三方鉴权、trace_id、请求体大小限制、日志上下文。
  • 不建议每个请求无脑登录 CHIS。
  • 如果做 CHIS 会话准备,也应调用 ChisSessionManager.ensure_session(),由 session manager 决定复用或重登。

application service

  • 编排单条体检上报流程。
  • 编排 CHIS 只读查询验证流程。
  • 处理幂等查询、业务校验、调用 mapper、调用 CHIS client。
  • 将 CHIS 错误翻译为本项目统一错误。

mapper / transformer

  • 将第三方输入转换为内部标准模型。
  • 将内部标准模型转换为 CHIS 请求体。
  • 管理字段默认值、字典映射、日期格式、空值策略。
  • 重点参考 HealthCheckHtmlForm.js 中 getSaveRequest 和 saveToServer 的行为。

CHIS auth manager

  • 负责登录 CHIS、获取角色 / 应用 / 会话上下文。
  • 负责查询当前账号信息或等价接口,判断会话是否有效。
  • 负责 Redis 会话缓存、清理和重登。
  • 登录链路参考 D:\hans\chupd\chis\login_client_v2.py,但不能原样依赖 Django model/cache。
  • CHIS public key 从 Flask 配置或环境变量读取,不从代码硬编码。

CHIS client

  • 封装 *.jsonRequest 和其他 CHIS HTTP 请求。
  • 自动携带会话 cookie 和必要 header。
  • 读取 CHIS_PROXY:配置为空时直连;配置有值时对 CHIS 登录、账号信息查询和 *.jsonRequest 统一使用代理。
  • 代理只作用于出站访问 CHIS,不代理第三方系统访问本项目的入站请求。
  • 处理超时、重试、登录失效、错误码、日志脱敏。
  • 先用 getLanderInfo、getEncryType、getHMNIListOfHTML 等只读接口验证通道,再接入保存接口。

Redis repository

  • 保存 CHIS 会话对象。
  • 保存幂等键和处理结果摘要。
  • 可保存短期锁,避免同一账号并发重登。

logging / archive

  • logs/ 保存运行日志:每天一个综合日志文件,包含 INFO、WARNING、ERROR、EXCEPTION 等不同级别记录,保留 1 年。
  • 运行日志只记录摘要:trace_id、接口、耗时、状态、错误码、CHIS service/action、必要定位字段。
  • archives/ 保存请求归档:一个 API 请求一个 archive JSON 文件,保存该次 API 请求 / 响应以及期间所有 CHIS 请求 / 响应。
  • archive 文件不脱敏,用于部署在内网前置机后的本地审计和故障排查。
  • archive 写入不应影响主业务成功 / 失败判定;写入失败必须记入运行日志。
  • archive 文件必须原子写入:先写 .tmp,完整落盘后 rename 为 .json。
  • logs/ 与 archives/ 必须加入 .gitignore,不得进入代码仓库。
  • 上线前必须评估磁盘容量;保留 1 年需要有清理任务或运维策略。

三、建议项目结构

chisup/
├── app/
│   ├── __init__.py        # create_app(config_object=None)
│   ├── api/
│   │   └── health_check.py
│   ├── middleware/
│   ├── services/
│   │   ├── health_check_query.py
│   │   └── health_check_submit.py
│   ├── mappers/
│   │   └── health_check.py
│   ├── chis/
│   │   ├── auth.py
│   │   ├── client.py
│   │   ├── crypto.py
│   │   ├── session_store.py
│   │   └── errors.py
│   ├── repositories/
│   ├── validators/
│   └── config.py
├── tests/
├── docs/
├── logs/             # 运行时生成,不提交 git
├── archives/         # 运行时生成,不提交 git,保存原始敏感归档
├── reverse_file/
├── requirements.txt
└── README.md

四、核心数据对象

4.1 第三方上报请求

具体字段待定,建议至少包含:

字段 说明
request_id 第三方业务流水号,用于幂等
account_ref CHIS 账号或机构配置引用;不推荐直接传明文密码
person.id_card 居民身份证号,日志必须脱敏
check_date 体检日期
health_check 体检主体数据
source 第三方来源系统

4.2 Redis CHIS 会话对象

建议结构:

{
  "base_url": "CHIS_BASE_URL_ALIAS",
  "uid": "CHIS_USER_ID",
  "role_id": "CHIS_ROLE_ID",
  "manage_unit": "CHIS_MANAGE_UNIT",
  "cookies": {},
  "login_at": "2026-07-04T00:00:00+08:00",
  "expires_at": "2026-07-04T02:00:00+08:00",
  "last_validated_at": "2026-07-04T00:10:00+08:00"
}

不要保存明文密码。确需保存账号凭证时,应使用安全配置或密钥管理,并在文档中明确加密和权限边界。

4.3 CHIS 体检保存请求

从逆向脚本可确认体检保存不是单表直传,至少涉及:

  • hcData
  • 生活方式数据
  • 查体数据
  • 辅助检查数据
  • 健康评价 / 指导数据
  • 用药、住院、非免疫规划接种等列表数据

最终字段以真实 CHIS 请求和 schema 验证为准。

4.4 CHIS 体检详情查询请求

已确认 reverse_file/20260704_query_health_check.har 中的体检详情查询需要:

{
  "serviceId": "chis.healthCheckService",
  "method": "execute",
  "serviceAction": "getHMNIListOfHTML",
  "schema": "chis.application.hc.schemas.HC_HealthCheck",
  "body": {
    "healthCheck": "体检主键",
    "phrId": "健康档案号",
    "idCard": "身份证号"
  }
}

检查报告信息查询需要:

{
  "serviceId": "chis.healthCheckService",
  "serviceAction": "getCheckInfoDetail",
  "method": "execute",
  "body": {
    "idCard": "身份证号",
    "checkDate": "体检日期"
  }
}

注意:当前资料不能证明“只传 healthCheck 就能查详情”。若外部 API 要支持只传体检 id,需要先验证如何由 healthCheck 反查 phrId、idCard、checkDate、empiId、createUser。

4.5 请求归档文件

archive 文件按日期和接口分层保存,建议路径:

archives/
└── YYYY/
    └── MM/
        └── DD/
            └── api-name/
                └── YYYYMMDD_HHMMSS_trace_<trace_id>_req_<request_id>.json

文件名至少包含:

  • 日期时间。
  • API 名称或安全化后的接口标识。
  • trace_id。
  • 第三方 request_id;没有时使用服务端生成的唯一值。
  • 可选:healthCheck 等业务定位字段。

文件内容格式:

{
  "meta": {
    "trace_id": "TRACE_ID",
    "api": "POST /api/v1/health-checks/query-detail",
    "request_id": "third-party-request-id",
    "created_at": "2026-07-04T21:15:30+08:00",
    "duration_ms": 1234,
    "result": "success"
  },
  "api": [
    {
      "request": {},
      "response": {}
    }
  ],
  "chis": [
    {
      "service_id": "chis.healthCheckService",
      "service_action": "getHMNIListOfHTML",
      "request": {},
      "response": {},
      "duration_ms": 456
    }
  ]
}

约束:

  • archive 保存完整原始数据,不脱敏。
  • archive 目录只能在内网前置机本地受控访问,禁止通过 API 静态暴露。
  • archive 中允许保存 CHIS 请求和响应原文,但不得提交到 git、测试快照或公开文档。
  • archive 文件保留 1 年,过期清理策略后续在部署任务中落地。

五、关键技术难点

难点 说明 应对
CHIS 登录链路 可能涉及公钥、加密、角色、应用、机构上下文 等用户提供现有代码后接入,先写 auth 边界
CHIS 网络代理 部署在内网前置机时,访问 CHIS 可能必须走 SOCKS5 使用可选 CHIS_PROXY 配置;空值直连,有值时为 http / https 同时设置 requests proxies
会话有效性 cookie 存在不代表 CHIS 会话仍有效 用账号信息查询接口确认,失败则清理缓存并重登
只传体检 id 查询详情 getHMNIListOfHTML 还需要 phrId 和 idCard 先要求调用方传全参数,后续验证反查链路
体检字段转换 CHIS 前端保存逻辑复杂,数据块多 先做最小样例 mapper,逐步补字段测试
幂等 第三方重试可能导致重复体检记录 使用 source + request_id 或业务唯一键保存结果
隐私与日志 / 归档 日志只存摘要,archive 保存完整原始敏感数据 logs/ 每天滚动且摘要化;archives/ 不脱敏但本地受控、原子写入、保留 1 年、不进 git
CHIS 接口变化 逆向接口可能因版本变化失效 client 层集中封装,转换层有测试样例

六、推荐开发顺序

  1. 初始化 Flask 项目骨架和测试命令。
  2. 接入 CHIS 登录代码,验证能获取有效会话。
  3. 实现账号信息查询 / 会话有效性确认。
  4. 实现 Redis 会话缓存、锁和失效重登。
  5. 实现通用 CHIS *.jsonRequest client。
  6. 先跑通体检详情只读查询,验证登录、会话、角色/机构、SM2 加密和错误处理。
  7. 定义第三方体检上报 API 和统一响应。
  8. 实现最小体检 mapper。
  9. 通过通用 CHIS request 提交最小样例。
  10. 补幂等、日志 / archive、错误码和测试。