企业微信 uni-app H5:OAuth 回退白屏与列表缓存
第三方 BI 报表项目,企业微信内嵌 H5,uni-app 编译,history 模式。主页面 BiLink 同时承担静默授权和列表展示,上线后碰到两个问题:授权完清掉 URL 参数,iOS 侧滑返回还是白屏;列表加了缓存以后,刷新行为又不对。
场景说明
从企业微信工作台点进来,走 snsapi_base 静默授权。getUserInfo 拿到数据后按权限分组出 Grid(集团 / 销售 / 事业部),点击 navigateTo 到 pages-sub/bi-links/details,web-view 打开 extLink。没有单独的授权页,OAuth 回调直接落在 BiLink,URL 带 code,换票后 replaceState 清参。
页面配置:
{
layout: 'default',
style: {
navigationBarTitleText: 'BI报表',
navigationStyle: 'custom',
},
}
整体流程:
打开 BiLink(无 code)
→ redirectToOAuth()
→ 带 code 回到 BiLink
→ initPage():getUserInfo → 写 bi-cache → replaceState
→ 出列表;只有一个报表则 reLaunch 进 details
进报表时带 autoRefresh=false,列表留在页面栈里,回来读缓存:
const url =
`/pages-sub/bi-links/details?title=...` +
`&autoRefresh=false` +
`&extLink=...`
uni.navigateTo({ url })
// onLoad
const autoRefresh = getUrlParam('autoRefresh')
if (autoRefresh !== 'false') {
state.initPage()
} else {
const cached = getBiReportGroupsCache()
if (cached?.length) {
state.reportGroups = cached
state.isLoading = false
window.history.replaceState({}, '', getCleanPageUrl())
} else {
state.initPage()
}
}
initPage 的 finally 里会 clearOAuthState(),再 replaceState 到 getCleanPageUrl()。授权封装在 useAuth 里,code 也会存一份到 sessionStorage(bi_auth_code)。
问题现象
侧滑返回白屏
列表正常出来后,企业微信 iOS 里左滑返回,页面空白。再 redirectToOAuth 或 replaceState 没用,有时得关掉重进。这里没用 uni.redirectTo,就是原页 replaceState,一样中招。
缓存和刷新
报表跳转带 autoRefresh=false,列表数据走 bi-cache:
- 列表 F5:URL 上没有
code也没有autoRefresh=false,重新initPage(),没 code 又去 OAuth,像刷新坏了; - 报表
navigateBack回来:onLoad不重跑,onShow里只调了hideShareMenu(),实例没了或缓存空了列表出不来; - 报表页刷新:
web-viewtoken 过期,白屏或 403。
原因
OAuth 走的是浏览器历史,不只是 uni-app 页面栈。
history 模式,回调地址类似 https://domain.com/pages/bi-links/index?code=xxx。整页跳转下来,浏览器历史大致是:
BiLink(无 code)
→ 企业微信 OAuth(302)
→ BiLink(带 code)
→ replaceState 清参 ← 只改栈顶,下面几条还在
redirectToOAuth 整页跳,历史会叠;replaceState 只动当前这一条。iOS 侧滑回的是浏览器栈,不一定走 navigateBack,容易回到还带 code 的地址——code 只能用一次,页面起不来就白了。
单页接回调的好处是链路短,坏处是 OAuth 前后同一个页面,replaceState 删不掉 302 产生的下层历史。用户已经滑回旧 URL,你再 replaceState,改的不一定是他眼前那一层,所以会觉得 replace「又不生效」。
autoRefresh=false 本来是想解决「从报表返回别重新鉴权」,不是给 F5 用的:
- 首次 / 带 code:
initPage(),正常; navigateBack:不触发onLoad,靠内存 state 和 bi-cache;- F5 刷列表:又进
initPage(),没 code 就 OAuth; - F5 刷报表:details 自己一套,跟列表缓存没接上。
onShow 目前没管缓存恢复。另外 history 部署记得配 try_files 回 index.html,不然回退到某些路径直接 404,也是白屏。
处理方向
换票后别只 replaceState
地址栏好看用 replaceState 够了;想少踩回退,换票成功后可以直接:
window.location.replace(getCleanPageUrl())
或者缓存写完后 uni.reLaunch({ url: '/pages/bi-links/index?autoRefresh=false' })。单报表那条已经 reLaunch 了,多报表列表授权完也该硬跳一次。
popstate 兜底
#ifdef H5,滑回带 code 的 URL 时纠正一下:
window.addEventListener('popstate', () => {
const code = getUrlParam('code')
const hasCache = getBiReportGroupsCache()?.length
if (code) {
hasCache ? window.location.replace(getCleanPageUrl()) : redirectToOAuth()
return
}
if (!hasCache && !sessionStorage.getItem('bi_auth_code')) {
redirectToOAuth()
}
})
列表页可以加 "disableSwipeBack": true。
分开处理「回调落地」和「从报表回来」
autoRefresh=false 只留给子页返回读缓存。F5 先看有没有有效 session,有的话只拉 permissions,别一见没 code 就 OAuth:
onLoad(() => {
hideShareMenu()
const code = getUrlParam('code')
const fromBack = getUrlParam('autoRefresh') === 'false'
if (code) {
state.initPage()
return
}
if (fromBack) {
const cached = getBiReportGroupsCache()
if (cached?.length) {
state.reportGroups = cached
state.isLoading = false
window.history.replaceState({}, '', getCleanPageUrl())
return
}
}
if (hasValidSession()) {
state.initPageFromSession()
} else {
state.initPage()
}
})
onShow 补缓存,报表 web-view 加 key
onShow(() => {
hideShareMenu()
if (!state.reportGroups.length && !state.isLoading) {
const cached = getBiReportGroupsCache()
if (cached?.length) state.reportGroups = cached
}
})
<web-view v-if="reportUrl" :key="reportKey" :src="reportUrl" />
Nginx
location / {
try_files $uri $uri/ /index.html;
}
参考
相关文章
企业微信与小程序工单问题
企微师傅端与商家小程序端长期共用一套代码,页面与组件嵌套边界不清晰、引入规范缺失、公共代码与端侧代码耦合度高,导致维护成本持续上升。本文给出拆分为两套独立项目的架构建议,并说明边界划分、迁移注意事项与性能优化方向。
GridView 宫格加载渲染优化
系统首页 GridView 宫格模块接口耗时不高,但首次进入总耗时接近 22s。复盘耗时分层定位过程、代码层面的瓶颈(约 2000 行、100 个 tab 重复节点)、优化手段与最终指标对比。
新商家系统性能优化实践
商家系统新版本上线后,团队持续针对构建效率与用户体验做了一轮系统性优化。本文记录核心方案与落地结果,供后续版本复用。
老系统升级与兼容改造实践
公司原有业务系统采用 Node + jQuery 架构,长期运行后暴露出典型遗留系统问题:
键盘弹起导致底部被顶起问题(H5 适配)
在移动端 H5 页面中,当用户聚焦 input、textarea 等可编辑元素、软键盘弹出时,常见表现包括:
防篡改水印
在各类管理后台、SaaS 平台或内部系统中,页面水印已经是非常常见的能力:一方面在截图时携带账号、姓名、时间等信息,降低截图外传的风险;另一方面在上传图片或文档预览时,通过水印标记上传者与时间,满足审计和合规需求。
Series
team documents
22 / 22