在 uni-app 面试中,“路由拦截”和“页面权限控制”是一道高频且能区分候选人项目经验深度的题目。不少开发者只停留在“用 uni.addInterceptor 拦截跳转”的层面,却忽略了页面栈、生命周期、登录态失效、白名单、tabBar 页面等实际场景。本文将从面试答题的角度,系统梳理 uni-app 中路由拦截与权限控制的完整方案。
一、先明确:uni-app 的路由机制与 Web 有何不同?
uni-app 的路由是基于页面栈管理的,而不是浏览器的 history。它提供了 navigateTo、redirectTo、reLaunch、switchTab、navigateBack 等 API。页面路径在 pages.json 中注册,分为普通页面和 tabBar 页面。
这意味着:
- 不能像 Vue Router 那样直接使用全局前置守卫
beforeEach。 - tabBar 页面只能用
switchTab跳转,且无法携带 query 参数。 - 页面栈最多 10 层,
navigateTo不能跳转到 tabBar 页面。
因此,路由拦截需要借助 uni-app 提供的拦截器 API,并结合页面生命周期做兜底。
二、核心方案:uni.addInterceptor 拦截路由 API
uni-app 从 2.6.0 起支持 uni.addInterceptor,可以拦截 navigateTo、redirectTo、reLaunch、switchTab、navigateBack 等 API。
基本用法
// utils/permission.js
const whiteList = ['/pages/login/index', '/pages/index/index']
function checkLogin() {
const token = uni.getStorageSync('token')
return !!token
}
function isWhiteList(url) {
const path = url.split('?')[0]
return whiteList.includes(path)
}
const routeInterceptor = {
invoke(args) {
const url = args.url || ''
if (isWhiteList(url)) return true
if (!checkLogin()) {
// 未登录,重定向到登录页,并记录目标页
uni.redirectTo({
url: `/pages/login/index?redirect=${encodeURIComponent(url)}`
})
return false // 返回 false 阻止本次跳转
}
return true
},
success() {},
fail() {},
complete() {}
}
export function setupRouteInterceptor() {
['navigateTo', 'redirectTo', 'reLaunch', 'switchTab'].forEach(api => {
uni.addInterceptor(api, routeInterceptor)
})
}
在 App.vue 的 onLaunch 中调用 setupRouteInterceptor() 即可全局生效。
关键点说明
invoke返回false会阻止跳转,这是拦截的核心。switchTab也要拦截,否则用户可以直接进入 tabBar 中的“我的”等需要登录的页面。navigateBack一般不需要拦截,但可在返回后由页面onShow校验权限。- 白名单机制必不可少,登录页、注册页、首页等必须放行,否则会死循环。
三、登录态失效与重定向回跳
拦截时不仅要判断是否登录,还要处理“登录后回到原页面”的体验。
// 登录页 onLoad
onLoad(options) {
this.redirect = options.redirect ? decodeURIComponent(options.redirect) : ''
},
// 登录成功后
handleLoginSuccess() {
if (this.redirect) {
uni.redirectTo({ url: this.redirect })
} else {
uni.switchTab({ url: '/pages/index/index' })
}
}
注意:如果 redirect 指向的是 tabBar 页面,必须用 switchTab,否则会失败。可以在跳转前判断:
const tabBarPages = ['/pages/index/index', '/pages/mine/index']
const path = this.redirect.split('?')[0]
if (tabBarPages.includes(path)) {
uni.switchTab({ url: path })
} else {
uni.redirectTo({ url: this.redirect })
}
四、页面级权限控制:onShow + 角色判断
路由拦截只能覆盖通过 API 跳转的场景。如果用户通过物理返回键、小程序码、分享链接直接进入某个页面,拦截器可能不会触发。因此需要在页面生命周期中做二次校验。
// 需要权限的页面
onShow() {
const token = uni.getStorageSync('token')
const userInfo = uni.getStorageSync('userInfo')
if (!token) {
uni.redirectTo({ url: '/pages/login/index' })
return
}
// 角色权限
if (this.requiredRole && userInfo.role !== this.requiredRole) {
uni.showToast({ title: '无访问权限', icon: 'none' })
setTimeout(() => uni.navigateBack(), 1500)
}
}
更优雅的做法是封装一个 权限 mixin 或 自定义 hooks:
// mixins/auth.js
export default {
onShow() {
const { auth = false, role = '' } = this.$options
if (!auth) return
const token = uni.getStorageSync('token')
if (!token) {
uni.redirectTo({ url: '/pages/login/index' })
return
}
if (role) {
const userInfo = uni.getStorageSync('userInfo') || {}
if (userInfo.role !== role) {
uni.showToast({ title: '无权限', icon: 'none' })
uni.navigateBack()
}
}
}
}
页面中使用:
export default {
auth: true,
role: 'admin',
mixins: [authMixin]
}
五、tabBar 页面的特殊处理
tabBar 页面无法通过 navigateTo 进入,且 switchTab 不携带参数。常见需求是“未登录时点击‘我的’跳转到登录页”。
由于 tabBar 的点击事件无法直接拦截,通常有两种做法:
- 在 tabBar 页面的
onShow中校验,未登录则uni.redirectTo到登录页。 - 使用自定义 tabBar(如
uni-app的midButton或自定义组件),在点击时先判断登录态。
推荐第一种,简单可靠:
// pages/mine/index.vue
onShow() {
if (!uni.getStorageSync('token')) {
uni.redirectTo({ url: '/pages/login/index' })
}
}
六、面试答题要点总结
回答这道题时,建议按以下结构展开,体现系统性:
- 说明差异:uni-app 没有 Vue Router 的全局守卫,需用
uni.addInterceptor。 - 核心实现:拦截
navigateTo、redirectTo、reLaunch、switchTab,在invoke中判断登录态,返回false阻止跳转。 - 白名单:登录页、首页等必须放行,避免死循环。
- 重定向回跳:登录后回到原页面,注意 tabBar 页面用
switchTab。 - 兜底方案:页面
onShow中二次校验,防止物理返回、分享链接等绕过拦截。 - 角色权限:通过 mixin 或 hooks 统一处理,区分不同角色可访问的页面。
- tabBar 特殊处理:在 tabBar 页面的
onShow中校验登录态。
如果能进一步提到 动态路由(根据权限生成 pages.json 或使用 uni-simple-router 插件)、token 过期自动刷新、拦截器移除(uni.removeInterceptor)等,会是不错的加分项。
七、结语
uni-app 的路由拦截与权限控制,本质是“API 拦截 + 页面生命周期兜底 + 白名单与角色管理”的组合拳。面试中不要只背 API,而要讲清楚为什么需要多层防护、如何处理边界情况。掌握这套方案,不仅能应对面试,也能直接落地到实际项目中。
未经允许不得转载:任鹏个人博客 » uniapp 面试题:uni-app 中如何做路由拦截和页面权限控制?

