Vue SSR路由守卫处理指南与最佳实践
Vue SSR中的路由守卫特殊处理指南
服务端路由守卫的特殊处理
在Vue的服务器端渲染(SSR)场景中,路由守卫的行为与客户端存在显著差异,需要开发者特别注意处理方式。
核心差异点
- 无DOM环境:服务端执行时没有浏览器DOM API
- 单次执行:不像客户端可以多次触发导航
- 异步数据获取:需在渲染前完成所有数据准备
实践方案
// 服务端入口文件
export default context => {
return new Promise((resolve, reject) => {
const { app, router, store } = createApp()
// 设置服务器端router的位置
router.push(context.url)
// 等待路由解析完成
router.onReady(() => {
const matchedComponents = router.getMatchedComponents()
// 无匹配路由时reject
if (!matchedComponents.length) {
return reject({ code: 404 })
}
// 执行组件级守卫
Promise.all(matchedComponents.map(Component => {
if (Component.asyncData) {
return Component.asyncData({ store, route: router.currentRoute })
}
})).then(() => {
// 所有预取钩子完成后将store状态附加到上下文
context.state = store.state
resolve(app)
}).catch(reject)
}, reject)
})
}
关键建议:
- 将数据预取逻辑放在组件
asyncData
而非beforeRouteEnter
- 使用
router.onReady
确保初始路由解析完成 - 全局守卫中避免使用浏览器特定API
beforeRouteEnter
在SSR中的行为差异
客户端 vs 服务端对比
特性 | 客户端 | 服务端 |
---|---|---|
执行时机 | 导航确认前 | 仅初始请求时 |
访问组件实例 | 通过next(vm=>{}) | 不可用 |
异步支持 | 完全支持 | 需配合Promise使用 |
典型问题解决方案
场景:需要在进入路由前验证权限
// 错误做法(服务端不适用)
beforeRouteEnter(to, from, next) {
if (!localStorage.getItem('token')) {
next('/login')
} else {
next()
}
}
// 正确做法(SSR兼容)
beforeRouteEnter(to, from, next) {
if (process.client) {
// 客户端逻辑
if (!localStorage.getItem('token')) {
next('/login')
} else {
next()
}
} else {
// 服务端逻辑
const hasToken = to.matched.some(record => record.meta.requiresAuth)
if (hasToken && !context.req.headers.cookie?.includes('token=')) {
next.redirect('/login')
} else {
next()
}
}
}
实践建议:
- 使用
process.client
和process.server
区分环境 - 服务端通过请求头而非localStorage获取凭证
- 关键权限校验应在服务端中间件中提前处理
性能优化策略
- 守卫精简:服务端守卫应保持轻量,复杂逻辑移到API层
- 缓存策略:对公共路由实现服务端缓存
- 错误边界:统一处理守卫中的异常
// 全局错误处理示例
router.onError((err) => {
if (process.server) {
serverHandleError(err)
} else {
clientHandleError(err)
}
})
通过理解这些SSR特有的守卫行为差异,开发者可以构建出既安全又高性能的同构应用。记住服务端守卫的核心原则:尽早验证,快速失败,无状态处理。
评论已关闭