Files
app_03_pregnancy/docs/login-fix-plan.md

197 lines
5.8 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.
# H5 登录卡住问题分析与小程序端修复方案
---
## 一、问题描述
### 1.1 现象
从小程序跳转到 H5 页面后,页面一直显示"正在获取登录信息...",无法正常加载首页或引导页。
### 1.2 调试信息
H5 调试面板(`?debug=1`)输出:
```
url https://mp.yizhezhe.com/app_03/
isWxMp (空 — 实际为 true,因 false 渲染为空)
hasTokenParam (空 — URL 中无 token 参数)
step wx-postMessage-done (已发送 NEED_TOKEN 请求)
```
### 1.3 根因分析
H5 登录流程有三个路径:
| 分支 | 触发条件 | 预期行为 |
|------|---------|---------|
| URL 有 token | `?token=***` | 解码 token → 登录 → 跳首页 |
| 小程序环境 | 检测到 `MicroMessenger` + `miniprogram` | 发 `postMessage({NEED_TOKEN})` 等小程序响应 |
| 浏览器开发 | 其他情况 | 调 `dev-login` 自动登录 |
当前状态:URL **没有 token**,而是进入了第 2 条路。H5 向小程序发送了 `postMessage({ type: "NEED_TOKEN" })`,但**小程序侧没有监听和处理这条消息**,导致 H5 永远停在"正在获取登录信息..."。
---
## 二、修复方案
### 方案 A(推荐):打开 web-view 时直接带上 token
H5 不需要发 `NEED_TOKEN` 消息。每次打开 web-view 时,小程序直接把 token 拼到 URL 里。
```javascript
// 小程序侧 — 打开 web-view 的页面中
Page({
data: {
// 小程序自己的 token(通过 wx.login / 微信登录获取)
token: 'eyJ0e...Egnk',
},
onLoad() {
// 确保 token 已就绪后再打开 web-view
this.ensureToken().then(token => {
this.setData({ token });
});
},
async ensureToken() {
// 此处用小程序自己的登录逻辑获取 token
// 示例:如果已有缓存则用缓存,否则先登录
const cached = wx.getStorageSync('auth_token');
if (cached) return cached;
// 登录逻辑...
return token;
},
// WXML: <web-view src="{{webviewUrl}}">
get webviewUrl() {
const base = 'https://mp.yizhezhe.com/app_03/';
const token = this.data.token;
// 有 token 就加 ?token=,没有就不加(H5 会 fallback 到 dev-login)
return token ? `${base}?token=${encodeURIComponent(token)}` : base;
},
});
```
**优点:**
- 最简单直接,无额外消息通信
- H5 拿到 token 后一步到位完成登录
- 不需要修改 H5 端代码
---
### 方案 B:监听 NEED_TOKEN 消息后回传
如果 web-view 先打开(URL 不带 token),H5 检测到小程序环境后发 `NEED_TOKEN` 消息,小程序接收后把 token 写回 URL。
```javascript
// 小程序侧 — web-view 所在的页面
Page({
onLoad() {
// 确保小程序侧准备好接收 postMessage
},
// web-view 的 bindmessage 回调
onMessage(e) {
const data = e.detail.data || e.detail; // 兼容不同版本
console.log('web-view 消息:', data);
if (data.type === 'NEED_TOKEN') {
// 获取 token 并传递回 web-view
const token = this.getToken();
if (!token) {
console.error('token 未就绪,无法响应 NEED_TOKEN');
return;
}
// 方式 1: 重新加载 web-view 的 src(推荐)
const base = 'https://mp.yizhezhe.com/app_03/';
const webview = this.selectComponent('#webview');
// 注意: 小程序 web-view 不支持直接改 src,需要用 navigateTo 重新打开
wx.navigateTo({
url: `/pages/webview/webview?token=${encodeURIComponent(token)}`,
});
// 方式 2: 如果 web-view 通过页面参数传递 token(适合小程序自定义导航)
// 见方案 A,在打开时直接带上 token
}
},
getToken() {
return wx.getStorageSync('auth_token');
},
});
```
对应 WXML:
```html
<web-view
id="webview"
src="https://mp.yizhezhe.com/app_03/"
bindmessage="onMessage"
/>
```
**缺点:**
- 需要额外一轮消息通信,H5 会先显示"正在获取登录信息..."再刷新
- 小程序 `web-view` 组件没有直接修改 `src` 的 API,只能重新 `navigateTo`
- 用户体验不如方案 A 顺滑
---
## 三、推荐方案对比
| 维度 | 方案 A(URL 带 token) | 方案 B(消息回调) |
|------|-----------------------|------------------|
| 实现复杂度 | 低 | 中 |
| 用户体验 | 流畅(一步到位) | 有闪烁(页面刷新) |
| H5 端改动 | 不需要 | 不需要 |
| 小程序端改动 | 加 URL 拼接 | 加 bindmessage 回调 |
| 额外通信 | 无 | 一轮 postMessage |
| token 过期处理 | 打开时即携带最新 token | 可能携带过期 token 再等 NEED_TOKEN |
**结论:采用方案 A。**
---
## 四、H5 端问题关联修改
### 4.1 Debug 面板布尔值修复
当前 `DebugPanel` 渲染布尔值 `false` 时会因为 `{v || "(空)"}` 显示为空。需要改:
```tsx
// 当前(有 bug):
<td>{v || <span className="text-gray-500">(空)</span>}</td>
// 修复后:
<td>{v === false ? 'false' : v === true ? 'true' : v || <span className="text-gray-500">(空)</span>}</td>
```
### 4.2 `isWechatMiniProgram()` 废弃
如果小程序采用方案 A(打开时直接带 token),H5 不再需要 `isWechatMiniProgram` 检测和 `NEED_TOKEN` 消息发送逻辑。上线后可清理:
```typescript
// LoginPage.tsx — 删除以下代码段
if (isWechatMiniProgram()) {
try {
(window as any).wx?.miniProgram?.postMessage({ type: "NEED_TOKEN" });
} catch {}
setError("正在获取登录信息...");
return;
}
```
---
## 五、验证步骤
1. 小程序侧按方案 A 修改,确保打开 web-view 时 URL 带 `?token=***`
2. 访问 `https://mp.yizhezhe.com/app_03/?token=***&debug=1`
3. 检查调试面板:`hasTokenParam=true`、`step=decode-ok` 或 `step=fetch-ok`
4. 确认跳转到 `/home` 或 `/onboarding`
5. 关闭 `?debug=1` 正常使用
6. (可选)清理 DebugPanel 和 `isWechatMiniProgram` 相关代码