iOS 微信授权底栏
微信授权结束,整屏 H5 底部多出一条前进后退栏。我顺着跳转过程逐段测试,最后把授权挪到首屏之前,画面恢复正常。
最近在做一个公众号活动。开篇采用整屏构图,用户看完展示,再点“开始征途”登录。
初次打开很正常。微信授权一结束,返回页面,底部就多出一条前进后退栏。原本完整显示的按钮被截掉一块,上方文字也少半行。查看日志,视口高度从 774 降到 691,差了 83 个 CSS 像素。
我先去看跳转代码。前端路由已经用 router.replace(),登录也通过 location.replace() 发起。后端是 Go,跳往微信和授权回调都返回 302,外面再套一层 nginx 代理。这套流程看起来没什么问题,回到手机上,底栏照样出现。
网上常见的另一个办法是 WeixinJSBridge.call('hideToolbar')。我把它放到 Bridge 就绪后执行,又在页面上加一个手动按钮。自动调用没有效果,等十几秒再点按钮,底栏还是没动。日志能确认调用已经执行,却解释不了为什么画面没有变化。
多出来一条历史
接下来,我想知道历史记录究竟在哪一步增加。
原来的登录入口和回调接口直接返回 302,页面一闪就过去,没法在手机上看数据。我把这两个接口临时改成诊断页,进来先停住,记录 history.length,点“继续”再跳转。
第一段很正常。活动页到登录入口,历史长度都是 1。经过微信授权,再回到回调页,就变成 2,底栏也在这时出现。接着返回活动,历史长度保持 2。
额外那条记录出现在微信授权往返期间。两个继续按钮都用 location.replace(),也没能阻止它。
我又试着后退。回调页退回登录入口,后退箭头变灰,前进箭头亮起来,底栏没有消失。再点前进,旧回调又执行一遍,触发 state 校验失败。前进记录还在,已经用过的授权状态却不能再用。
折腾到这里,改跳转方法、调用隐藏接口、后退回原页面,都没能恢复整屏。我开始换个角度看入口。
以前是先显示活动,再去授权。如果第一次请求就直接去微信,回来才显示页面,会怎样?
我加了一个临时链接,发到微信聊天里。关闭当前网页,重新点开。服务端生成授权状态后直接返回 302,这次没有先显示开篇,也没有经过登录诊断页。
授权回来,回调页的历史长度是 1。底栏没有出现。点继续返回活动,历史长度也是 1,按钮完整显示。
| 打开方式 | 回调时 | 返回活动时 | 底栏 |
|---|---|---|---|
| 先显示页面,再授权 | 2 | 2 | 出现 |
| 首次请求直接授权 | 1 | 1 | 无 |
表中数字是 history.length。这轮测试让我确定,入口可以换一种走法。Go 原本就在返回 302,继续改 nginx 没有必要,先把授权前那张页面省掉。
从入口改起
正式代码新增一个服务端入口,负责检查登录会话。已有有效会话就进入 H5,没有会话或会话过期就发起微信授权。入口复用原有会话校验和授权函数。
func (a *Auth) entry(w http.ResponseWriter, r *http.Request) {
_, err := a.sessionUser(r)
if errors.Is(err, errSessionRequired) || errors.Is(err, errSessionExpired) {
a.login(w, r)
return
}
if err != nil {
authorizationFailure(w, r, 500, "读取用户会话失败", "service")
return
}
w.Header().Set("Cache-Control", "no-store")
http.Redirect(w, r, a.cfg.PublicURL+"/h5/", http.StatusFound)
}login 在同一次请求中准备授权参数,并返回微信授权 302。回调完成校验、创建会话后,自动跳到 /h5/。浏览器到这里才开始显示活动页面。
公众号菜单和对外链接都应该走这个入口。以示例域名表示,地址如下。
https://activity.example.com/api/h5/auth/entry路径也有一点讲究。项目里的登录 Cookie 使用 Path=/api/h5/,访问根路径 / 时,浏览器不会带上它。入口放在 /api/h5/auth/entry,就能读到现有 Cookie,根路径再跳转过来即可。Cookie 路径说明
这么改以后,用户点公众号链接时先完成授权,再看开篇。“开始征途”留在原位,不过不再承担登录跳转。如果项目要求看完开篇才能授权,就得重新考虑这个安排。
我也移除 H5 页面内再次发起授权的逻辑。会话失效时,页面提示关闭后从公众号入口重新进入,避免又绕回之前那条跳转链路。
最后,把临时诊断页和按钮删干净,回调恢复成自动 302,再从微信聊天新开正式入口。这回从授权一路走到开篇,页面顺着播到路线图,按钮完整显示,底栏没有再出现。
