5.8 KiB
5.8 KiB
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 里。
// 小程序侧 — 打开 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。
// 小程序侧 — 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:
<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 || "(空)"} 显示为空。需要改:
// 当前(有 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 消息发送逻辑。上线后可清理:
// LoginPage.tsx — 删除以下代码段
if (isWechatMiniProgram()) {
try {
(window as any).wx?.miniProgram?.postMessage({ type: "NEED_TOKEN" });
} catch {}
setError("正在获取登录信息...");
return;
}
五、验证步骤
- 小程序侧按方案 A 修改,确保打开 web-view 时 URL 带
?token=*** - 访问
https://mp.yizhezhe.com/app_03/?token=***&debug=1 - 检查调试面板:
hasTokenParam=true、step=decode-ok或step=fetch-ok - 确认跳转到
/home或/onboarding - 关闭
?debug=1正常使用 - (可选)清理 DebugPanel 和
isWechatMiniProgram相关代码