Angular Universal SSR下如何在app-routing.module.ts中使用platformId变量
解决方案
问题根因
你直接在模块顶层定义routes常量时处于静态初始化阶段,还未进入Angular依赖注入的运行时周期,无法直接拿到注入的PLATFORM_ID,且服务端运行环境不存在localStorage API,直接调用会报错。
方案1:使用路由守卫(全Angular版本兼容)
这是兼容性最好的方案,所有支持Angular Universal的版本都可以使用:
- 首先创建一个重定向守卫:
// src/app/redirect-home.guard.ts import { Injectable, Inject } from '@angular/core'; import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '@angular/router'; import { PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; @Injectable({ providedIn: 'root' }) export class RedirectHomeGuard implements CanActivate { constructor( @Inject(PLATFORM_ID) private platformId: Object, private router: Router ) {} canActivate( route: ActivatedRouteSnapshot, state: RouterStateSnapshot ): UrlTree | boolean { if (isPlatformBrowser(this.platformId)) { const countryCode = localStorage.getItem('countryCode') || 'my'; return this.router.parseUrl(`/${countryCode}`); } // 服务端环境直接走默认国别路径 return this.router.parseUrl('/my'); } }
- 修改
app-routing.module.ts的路由配置:
import { RedirectHomeGuard } from './redirect-home.guard'; const routes: Routes = [ { path: '', pathMatch: 'full', canActivate: [RedirectHomeGuard] }, // 保留你原有其他路由配置 ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled', onSameUrlNavigation: 'reload' }) ], exports: [RouterModule] }) export class AppRoutingModule {}
方案2:使用Angular 14+ 注入式redirectTo函数
如果你使用的是Angular 14及以上版本,可以直接使用支持依赖注入的redirectTo函数写法,代码更简洁:
// app-routing.module.ts import { NgModule, inject, PLATFORM_ID } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { isPlatformBrowser } from '@angular/common'; const routes: Routes = [ { path: '', pathMatch: 'full', redirectTo: () => { const platformId = inject(PLATFORM_ID); if (isPlatformBrowser(platformId)) { return localStorage.getItem('countryCode') || 'my'; } return 'my'; } } // 保留你原有其他路由配置 ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled', onSameUrlNavigation: 'reload' }) ], exports: [RouterModule] }) export class AppRoutingModule {}
注意事项
服务端渲染返回的路径需要和客户端首次渲染的路径保持一致,避免hydration不匹配报错,所以两种方案默认服务端都返回/my路径。如果需要优化体验,你也可以在服务端通过请求头的Accept-Language或者IP解析获取用户国别,替代默认的my参数,避免客户端二次跳转。
内容的提问来源于stack exchange,提问作者Bhavya
相关产品推荐
相关产品推荐

