Vue SSR中的路由守卫特殊处理指南

服务端路由守卫的特殊处理

在Vue的服务器端渲染(SSR)场景中,路由守卫的行为与客户端存在显著差异,需要开发者特别注意处理方式。

核心差异点

  1. 无DOM环境:服务端执行时没有浏览器DOM API
  2. 单次执行:不像客户端可以多次触发导航
  3. 异步数据获取:需在渲染前完成所有数据准备

图1

实践方案

// 服务端入口文件
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)
  })
}

关键建议

  1. 将数据预取逻辑放在组件asyncData而非beforeRouteEnter
  2. 使用router.onReady确保初始路由解析完成
  3. 全局守卫中避免使用浏览器特定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()
    }
  }
}

实践建议

  1. 使用process.clientprocess.server区分环境
  2. 服务端通过请求头而非localStorage获取凭证
  3. 关键权限校验应在服务端中间件中提前处理

性能优化策略

  1. 守卫精简:服务端守卫应保持轻量,复杂逻辑移到API层
  2. 缓存策略:对公共路由实现服务端缓存
  3. 错误边界:统一处理守卫中的异常
// 全局错误处理示例
router.onError((err) => {
  if (process.server) {
    serverHandleError(err)
  } else {
    clientHandleError(err)
  }
})

通过理解这些SSR特有的守卫行为差异,开发者可以构建出既安全又高性能的同构应用。记住服务端守卫的核心原则:尽早验证,快速失败,无状态处理

评论已关闭