uni.addinterceptor 能拦截小程序端页面跳转,但仅限主动调用 navigateto 等四个 api 的场景;对 tabbar 点击、分享唤醒、冷启动等绕过 js 层的行为无效。

uni.addInterceptor 能拦截小程序端的页面跳转吗
能,但仅限于主动调用 uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab 这四个 API 的场景;uni.addInterceptor 在微信小程序中对 navigateTo 等有效,但对 tabBar 点击、分享卡片唤醒、后台冷启动直达页面等行为不生效——这些路径绕过了 JS 层跳转调用,拦截器根本收不到事件。
为什么小程序里 args.url 经常匹配失败
因为小程序端传入的 args.url 可能是相对路径(如 '../login/login')、不含 pages/ 前缀(如 '/tabBar/mine'),或带未 decode 的 query(如 '/pages/detail?id=%2Fuser%2Fprofile')。直接拿它跟白名单比对必然漏判。
- 统一 normalize:用
new URL(args.url, 'https://a.b').pathname或手动补前缀 + 截断 query:args.url.split('?')[0].replace(/^\.\.\//, 'pages/').replace(/^\/tabBar/, 'pages/tabBar') - 白名单必须写绝对路径且与
pages.json严格一致(大小写、斜杠方向、无 .vue 后缀) - tabBar 页面的
uni.switchTab拦截需单独处理路径前缀,不能复用navigateTo的逻辑
在 invoke 钩子里执行业务逻辑的硬约束
invoke 是唯一可同步干预跳转的钩子,但它的执行上下文极受限:不能发网络请求、不能读取异步 store、不能等待 uni.getStorage 回调——所有校验必须基于同步缓存(如 uni.getStorageSync('token'))完成。
- Token 校验必须显式判断:
typeof token === 'string' && token.trim().length > 0,不能只用!!token - 过期时间字段(如
exp)若来自后端 JWT,需先JSON.parse()再取值,且注意单位是秒还是毫秒(Date.now() > exp * 1000) - 禁止在
invoke里调用uni.navigateTo后再return false,这会触发无限递归;正确做法是修改args.url后return args
如何兜住小程序冷启动和 tabBar 点击的漏网之鱼
拦截器无法覆盖的场景,必须靠页面级防御:每个需要鉴权的页面在 onLoad 里做二次检查,并用 uni.getCurrentPages() 判断是否已处于登录流程中,避免重复跳转。
- 冷启动时,
App.vue的onLaunch只执行一次,无法响应后续任意页面跳转,但它可以预加载 token 并设置全局标志位 - tabBar 页面本身不走
switchTab拦截器?那就把鉴权逻辑下沉到对应页面的onShow,并配合uni.getStorageSync('redirectUrl')做回跳还原 - 分享卡片带参数直达业务页?在目标页面
onLoad解析options,发现缺失 token 就立即uni.reLaunch({ url: '/pages/login/login?redirect=' + encodeURIComponent(currentUrl) })
真正难的不是写拦截器,而是把「路径标准化」「缓存有效性判断」「冷热启动差异」「多端路径表现」这几件事在同一个函数里稳住——稍有松动,用户就会在某个入口点直奔白屏或无限跳登录页。











