T40 UI 审计修复(60 页面全覆盖): - 新增 $acc-d/$wrn-d 渐变中间色变量,修复首页轮播渐变硬编码 - 替换 8 处裸 white 为 $white 设计变量(5 个 SCSS 文件) - 修复 7 处触摸目标 40/44px → 48px(健康/消息/咨询/预约/首页) - 3 页面新增 Loading 状态(体征录入/个人中心/就诊人添加) - statusTag 移除硬编码布局值,改用 SCSS mixin 控制 - 医生端 14 页面架构 Hook 层补充(useThrottledDidShow 替换 useEffect) - 移除 action-inbox 未使用 import 安全 P0 修复: - JWT 中间件加固:token 类型校验 + 过期预检 + 类型别名简化 - 速率限制增强:滑动窗口 + 暴力破解防护 - analytics handler 错误处理完善 文档: - T40 审计报告(24 PASS / 36 PASS_WITH_ISSUES / 0 NEEDS_WORK) - 5 份 DevTools/性能审计讨论记录 - wiki 症状导航 + 小程序章节更新
4.4 KiB
DevTools 卡死根因分析与修复
日期: 2026-05-14 | 参与者: AI 辅助分析
背景
微信小程序在 DevTools 中频繁卡死,表现为:
- 所有 API 请求失败(
ERR_SSL_PROTOCOL_ERROR) - Tab 切换后页面长时间无响应(30s+)
- 登录流程点击无反应
- DevTools 完全失去响应需强制关闭
根因分析
根因 1(CRITICAL):http→https 自动转换
文件: apps/miniprogram/src/services/request.ts
// 旧代码:production 模式自动将 http 替换为 https
if (process.env.NODE_ENV === 'production' && url.startsWith('http://')) {
return url.replace('http://', 'https://');
}
问题: taro build --type weapp 默认是 production 构建。所有 API 请求从 http://localhost:3000 被强制改为 https://localhost:3000,而后端只支持 HTTP。每个请求都失败 → 错误处理循环 → React 重渲染 → 内存增长 → DevTools 卡死。
修复: 移除自动协议升级,让 .env 文件作为 URL 唯一来源。
根因 2(CRITICAL):getHeaders 中的同步 Token 刷新
文件: apps/miniprogram/src/services/request.ts
// 旧代码:每个请求前 await tryRefreshToken()
async function getHeaders() {
if (expiresAt && Date.now() > expiresAt - 60_000) {
await tryRefreshToken(); // 15 秒超时
refreshHeadersCache();
}
}
问题: 健康页 didShow 触发 4 个并发 API 请求,每个都先 await getHeaders()。当 Token 接近过期时,所有请求同时卡在 tryRefreshToken() 上。如果 refresh 超时(15 秒),加上 401 重试再超时(15 秒),总计 30 秒无响应。
修复: 移除 getHeaders() 中的 Token 刷新预检查,仅依赖已有的 401 重试逻辑(request 函数中 status === 401 时触发 tryRefreshToken())。
根因 3(HIGH):DevTools 中 getPhoneNumber 不工作
文件: apps/miniprogram/src/pages/login/index.tsx
问题: 微信登录流程需要两步:
Taro.login()→ 获取 code → 后端返回bound: false(mock openid 不在 DB)<Button openType='getPhoneNumber'>→ 微信手机号授权弹窗 → 绑定手机号
在 DevTools 中,getPhoneNumber 可能不弹出授权弹窗(或被限频 invoke getPhoneNumber too frequently),导致登录流程卡死在第二步。
修复: dev 模式新增"开发模式快速登录"按钮,直接调用 bindPhone('dev_mock_encrypted', 'dev_mock_iv') 绕过手机号授权。后端 dev_mode 下会自动生成 mock 手机号。
患者端页面性能审查
对全部患者端页面进行了六维度审查:
| 风险 | 严重程度 | 文件 | 描述 |
|---|---|---|---|
| 咨询详情页长轮询 | CRITICAL | consultation/detail/ | 递归 setTimeout 轮询(已有保护:3s 间隔 + 50 次失败上限 + useDidHide 暂停) |
| 首页 5 个并发 API | MEDIUM | index/ | didShow 触发 refreshToday + loadReminders(3 子请求) + loadUnread |
| 健康页 4 个并发 API | MEDIUM | health/ | didShow 触发 refreshToday + loadTrend + loadAiSuggestions + getHealthThresholds |
| 兑换页 page_size=100 | MEDIUM | pkg-mall/exchange/ | 请求过大量数据 |
| 咨询消息渲染 200 条 | MEDIUM | consultation/detail/ | DOM 节点上限偏高 |
修复清单
| 修复 | 文件 | 状态 |
|---|---|---|
| 移除 http→https 自动转换 | services/request.ts |
已完成 |
| 移除 getHeaders 同步 Token 刷新 | services/request.ts |
已完成 |
| 新增 dev 快速登录按钮 | pages/login/index.tsx + index.scss |
已完成 |
| JWT 中间件 scope 缓存 60s | erp-auth/middleware/jwt_auth.rs |
已完成 |
| Redis 失败缓存 5s | erp-server/middleware/rate_limit.rs |
已完成 |
遗留问题
- banner-image 500:
/public/banner-image/{id}返回 500(测试数据媒体文件不在磁盘上) - 首页首次加载慢: 首次 Tab 切换可能需要几秒加载时间(5 个并发 API),但不卡死
- MCP 超时: MCP 的 switchTab/reLaunch 操作可能导致 DevTools 暂时无响应(MCP 工具本身的限制)
结论
DevTools 卡死的根因是 request.ts 中的两个设计缺陷叠加:
- 所有请求被强制改为 HTTPS(后端不支持)→ 全部失败
- 并发请求全部阻塞在 Token 刷新预检查上 → 长时间无响应
两个修复都是"减法"——移除不必要的自动升级和预检查,让系统更简单、更可靠。