fix(身份): 宿主页「拿到 openid 才加载 H5」+ 复用 App.vue 并行登录(不重复换 code)
背景(2026-09-20 线上排查):删掉小程序缓存重进时 H5 以访客态加载(孕周 `--`、档案空、
跳应用不带 openid,实测跳授权示例是裸 URL)。服务端证据:该设备只打了 `/api/mp/apps`,
没有任何带 openid 的 profile/pregnancy 调用 —— 宿主那次没注入身份,不是数据丢了。
根因:
1) App.vue 静默授权只处理 token 分支:v2/wechat/silence_auth 对新用户 / 强制绑定手机号返回
{auth_login:1, key, openid, unionid}(无 token),openid 被丢掉;且 res.data.userInfo 缺失时
取 .uid 会抛异常把后续 commit 一起带走。
2) 两个宿主页只从 store.openid / 缓存 OPENID / JWT 读身份,读不到就匿名加载(首页壳不等不重试,
容器页 _finalizeUrl / _fetchOpenidAndLoad 兜底)。
改法:
- App.vue:补「无 token 但有 openid」分支(SET_OPENID + 缓存,unionid 同理);userInfo 判空;
**并把这次静默登录的 promise 挂到 globalData._silenceAuthPromise**(供宿主页复用,见下)。
- mixins/webviewHost.js:新增
· _silenceAuthOpenid()(wx.login → v2/wechat/silence_auth,兼容 auth_login/userInfo/JWT 三种
openid 来源,拿到即落 store + 缓存,带 8s 超时保险丝);
· _awaitHostLogin(timeout)(等 App.vue 那次登录结束,**不重复换 code**)。
- 两个宿主页统一 fail-closed「拿到 openid 才加载」,并且**第 1 次先 await App.vue 的并行登录**、
命中缓存就直接加载;之后才自己取。**网络尝试上限 3 → 2,退避 600×n → 固定 500ms**
(实测:code2session 约 200–300ms,重复换一次就是白花这个钱;最坏等待从 ~3.5s 降到 ~1–2.5s)。
- 首页壳:读不到身份就不设 webUrl(停在小程序自己的加载屏,文案分「取身份中/失败/页面加载失败」三态);
2 次仍失败 → 「未获取到微信身份」+「重新获取身份」。
- 容器页:三条失败分支(有 token 无 openid 的重试失败、无 token 无 openid、onShow 仍无 openid)
全部改走 _ensureIdentityThenLoad();删除本页重复实现的 _fetchOpenidAndLoad;新增兜底屏
(以前 url 为空是白屏)。非可信域(商城自身域名等)不注入身份、照常直接加载。
- utils/util.js:注释里的方法名同步(_fetchOpenidAndLoad → _ensureIdentityThenLoad)。
⚠️ 提交同时包含这两处**此前已存在的未提交 WIP**(同文件、改动交织):pages/annex/web_view/index.vue
的 mixin 重构(handleMessage→handleHostMessage 等 4 处 handler 改名)与 pages/index/index.vue
的两行 tabBar 调整。
⚠️ 刻意 fail-closed:CRMEB silence_auth 整体不可用时会停在失败屏而不是降级加载。
⚠️ 未动 manifest.json 版本号(见另一次改动:已统一为 0.3.6 / 36)。
This commit is contained in:
38
App.vue
38
App.vue
@@ -227,7 +227,7 @@
|
||||
let that = this;
|
||||
let spid = that.globalData.spid ? that.globalData.spid : '';
|
||||
console.log('[auth-flow] silenceAuth 发起, code=' + (code ? code.substring(0, 10) + '...' : '(空)'));
|
||||
silenceAuth({
|
||||
const authPromise = silenceAuth({
|
||||
code: code,
|
||||
spread_spid: spid,
|
||||
spread_code: that.globalData.code
|
||||
@@ -241,11 +241,30 @@
|
||||
token: res.data.token,
|
||||
time: time
|
||||
});
|
||||
that.$store.commit('SETUID', res.data.userInfo.uid);
|
||||
that.$store.commit('UPDATE_USERINFO', res.data.userInfo);
|
||||
/* ⚠️ 2026-09-20:`userInfo` 不是每个响应都有(v2/wechat/silence_auth
|
||||
只回 token+expires_time),直接取 `.uid` 会抛异常,把后面的
|
||||
commit 一起带走。加一层判空,缺了也不影响身份(openid 由 LOGIN 从 JWT 解出)。 */
|
||||
if (res.data.userInfo) {
|
||||
that.$store.commit('SETUID', res.data.userInfo.uid);
|
||||
that.$store.commit('UPDATE_USERINFO', res.data.userInfo);
|
||||
}
|
||||
console.log('[auth-flow] ✅ silenceAuth 成功, token 已存 store (含 openid)');
|
||||
} else if (res.data.openid) {
|
||||
/* ⚠️⚠️ 2026-09-20 修:新用户 / 后台开启了「强制绑定手机号」时,
|
||||
该接口返回的是 {auth_login:1, key, openid, unionid} —— **有 openid、没有 token**。
|
||||
以前这段落到下面的 else,只打一条警告就把 openid 丢了;于是
|
||||
store.openid / 缓存 OPENID / JWT 三处全空,首页壳 _hostOpenid() 拿不到身份
|
||||
→ **匿名加载 mama-box**(H5 进访客态:孕周 `--`、档案空、跳应用跳裸 URL)。
|
||||
这里必须把它落 store + 缓存。 */
|
||||
that.$store.commit('SET_OPENID', res.data.openid);
|
||||
try { uni.setStorageSync('OPENID', res.data.openid); } catch (e) {}
|
||||
if (res.data.unionid) {
|
||||
that.$store.commit('SET_UNIONID', res.data.unionid);
|
||||
try { uni.setStorageSync('UNIONID', res.data.unionid); } catch (e) {}
|
||||
}
|
||||
console.log('[auth-flow] ✅ 无 token 但拿到 openid,已缓存(首页壳据此注入身份): ' + String(res.data.openid).substring(0, 8) + '...');
|
||||
} else {
|
||||
console.warn('[auth-flow] ⚠️ silenceAuth 返回无 token:', JSON.stringify(res.data || res).substring(0, 200));
|
||||
console.warn('[auth-flow] ⚠️ silenceAuth 返回无 token 也无 openid:', JSON.stringify(res.data || res).substring(0, 200));
|
||||
}
|
||||
}).catch(err => {
|
||||
console.warn('[auth-flow] ❌ silenceAuth 失败:', JSON.stringify(err).substring(0, 300));
|
||||
@@ -253,6 +272,17 @@
|
||||
title: err
|
||||
})
|
||||
});
|
||||
/* ⚠️ 2026-09-20:把这次静默登录的 promise 挂到 globalData,
|
||||
让宿主页(首页壳 / 容器页)在缓存未命中时**先 await 它**、而不是自己再换一次 code
|
||||
(见 mixins/webviewHost.js 的 _awaitHostLogin)。
|
||||
动机:微信 code 一次性,两边各换一次要多花 200–300ms(实测 code2session 就这么贵),
|
||||
而 openid 本来就该由这一条链路落缓存(本文件上面的 SET_OPENID 分支 / LOGIN 从 JWT 提取)。
|
||||
settle 后清掉,避免下次误等一个已经结束的 promise。 */
|
||||
try { that.globalData._silenceAuthPromise = authPromise; } catch (e) {}
|
||||
authPromise.then(() => {
|
||||
try { if (that.globalData._silenceAuthPromise === authPromise) that.globalData._silenceAuthPromise = null; } catch (e) {}
|
||||
});
|
||||
return authPromise;
|
||||
},
|
||||
/**
|
||||
* 检测当前的小程序
|
||||
|
||||
Reference in New Issue
Block a user