# 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: 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 ``` **缺点:** - 需要额外一轮消息通信,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): {v || (空)} // 修复后: {v === false ? 'false' : v === true ? 'true' : v || (空)} ``` ### 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` 相关代码