Files
Mdeical_Sur_Report/工程分析/经验记录.md

3.8 KiB
Raw Blame History

经验记录

本文档用于沉淀项目修改过程中遇到的关键问题及解决方案。 每次执行工作流 Step 5 后,按四段式追加新记录。 执行修改前必须阅读本文档,避免重复踩坑。


记录格式

## [{Year}-{Mon}-{Day}-{Hour}-{Min}-{Sec}] 问题简述

### A. 具体问题
(描述遇到的现象或错误)

### B. 产生问题原因
(根因分析)

### C. 解决问题方案
(具体的解决步骤或代码改动)

### D. 后续如何避免问题
(预防措施、规范建议、检查清单项)

历史记录

[2026-04-20-10-14-09] Web Crypto API 异步性与 storage 同步接口冲突

A. 具体问题

需求要求将 systemSettings 的加密从 XOR 升级为 Web Crypto API AES-GCM同时维持 storage.get/set 的同步调用签名。但 crypto.subtle 的所有加解密操作均为异步 Promise若直接将 storage.get/set 改为 async将导致 ReportEditor.tsx、Login.tsx 等数十处调用点需要同步改为 await改动面极大且风险不可控。

B. 产生问题原因

Web Crypto API 是浏览器原生标准,设计为全异步 API无法像 crypto-js 那样提供同步调用。而项目早期设计时 storage 模块全部为同步接口,未预留异步扩展点。

C. 解决问题方案

采用"启动时预解密 + 内存缓存"的折中方案:

  1. storage.ts 中新增异步 init() 函数,在应用启动(main.tsxawait storage.init())时预解密 systemSettings 到模块级内存缓存 systemSettingsCache
  2. storage.get('systemSettings') 改为从缓存同步返回,storage.set('systemSettings') 改为更新缓存并触发异步持久化(不阻塞调用方)。
  3. 其他 key 的读写保持原样,完全不受影响。
  4. 该方案无需修改任何业务组件中 storage.get('systemSettings') 的调用方式。

D. 后续如何避免问题

  • 若未来再次遇到"必须引入异步存储操作"的需求,优先评估能否用"启动预加载 + 内存缓存"模式规避接口签名变更。
  • 若必须改异步接口,应将影响范围限制在单一 key如新增 getAsync/setAsync),而非全局改动 storage.get/set
  • 在需求分析阶段增加"接口兼容性影响评估"子项,提前识别同步/异步冲突。

[2026-04-20-10-14-09] 旧数据兼容密钥与"消除硬编码"验收标准冲突

A. 具体问题

安全加固的验收标准要求"构建产物中不再出现任何硬编码密钥字符串"。但实现 AES-GCM 迁移时,必须保留旧 XOR 密钥 MedicalReportSys2024 才能解密历史 localStorage 中的 systemSettings 数据。首次修改后构建产物扫描发现该字符串仍然存在。

B. 产生问题原因

数据迁移需求(兼容旧 XOR 密文)与安全需求(消除硬编码密钥)表面上互斥。根源在于旧密钥是以明文常量形式写死在源码中的,构建产物必然包含该字符串。

C. 解决问题方案

将旧 XOR 密钥同样移入构建阶段环境变量 LEGACY_STORAGE_KEY,通过 vite.config.tsdefine 注入:

  • 构建产物中不再包含固定的 "MedicalReportSys2024"
  • 若部署方需要兼容旧数据,在构建时配置 LEGACY_STORAGE_KEY="MedicalReportSys2024" 即可正常迁移。
  • 若部署方不需要兼容(全新部署),留空即可,旧数据将以 JSON.parse 失败处理,回退到 fallback。

D. 后续如何避免问题

  • 任何涉及历史数据迁移的安全重构,必须在方案设计阶段同步考虑"旧密钥/旧算法常量是否需要保留"。
  • 检查清单:若验收标准包含"构建产物无硬编码敏感字符串",则所有历史兼容所需的常量也必须环境变量化。
  • .env.example 中应显式标注 LEGACY_STORAGE_KEY 的用途("Former XOR encryption key"),避免运维人员误删。