Files
hms/docs/discussions/2026-05-14-devtools-freeze-root-cause-fix.md
iven 8f353946e1 fix(mp): T40 UI 审计修复 — 28 项设计系统合规 + 安全加固 + 讨论记录
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 症状导航 + 小程序章节更新
2026-05-14 23:12:54 +08:00

95 lines
4.4 KiB
Markdown
Raw 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.
# DevTools 卡死根因分析与修复
> 日期: 2026-05-14 | 参与者: AI 辅助分析
## 背景
微信小程序在 DevTools 中频繁卡死,表现为:
- 所有 API 请求失败(`ERR_SSL_PROTOCOL_ERROR`
- Tab 切换后页面长时间无响应30s+
- 登录流程点击无反应
- DevTools 完全失去响应需强制关闭
## 根因分析
### 根因 1CRITICALhttp→https 自动转换
**文件**: `apps/miniprogram/src/services/request.ts`
```typescript
// 旧代码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 唯一来源。
### 根因 2CRITICALgetHeaders 中的同步 Token 刷新
**文件**: `apps/miniprogram/src/services/request.ts`
```typescript
// 旧代码:每个请求前 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()`)。
### 根因 3HIGHDevTools 中 getPhoneNumber 不工作
**文件**: `apps/miniprogram/src/pages/login/index.tsx`
**问题**: 微信登录流程需要两步:
1. `Taro.login()` → 获取 code → 后端返回 `bound: false`mock openid 不在 DB
2. `<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` | 已完成 |
## 遗留问题
1. **banner-image 500**: `/public/banner-image/{id}` 返回 500测试数据媒体文件不在磁盘上
2. **首页首次加载慢**: 首次 Tab 切换可能需要几秒加载时间5 个并发 API但不卡死
3. **MCP 超时**: MCP 的 switchTab/reLaunch 操作可能导致 DevTools 暂时无响应MCP 工具本身的限制)
## 结论
DevTools 卡死的根因是 `request.ts` 中的两个设计缺陷叠加:
1. 所有请求被强制改为 HTTPS后端不支持→ 全部失败
2. 并发请求全部阻塞在 Token 刷新预检查上 → 长时间无响应
两个修复都是"减法"——移除不必要的自动升级和预检查,让系统更简单、更可靠。