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

5.8 KiB
Raw Blame History

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;
}

五、验证步骤

  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 相关代码