Angular Universal SSR迁移报错:Cannot read properties of undefined (reading 'subscribe')
问题分析与解决方案
核心问题定位
从报错「Cannot read properties of undefined (reading 'subscribe')」和日志输出来看,存在两个关键问题:
1. PostService中errorHandler上下文丢失
你在getPosts方法里使用catchError(this.errorHandler)时,直接传递方法引用会导致errorHandler内部的this指向丢失(变为undefined),请求出错时调用该方法会触发订阅相关的未定义错误。
2. Effects中调用浏览器端专属依赖Toastr
SSR环境下无法实例化Toastr这类浏览器端组件,执行this.toastr.error会抛出未定义错误,直接中断Observable流。
具体修复步骤
修复PostService的错误处理
两种方式解决this上下文丢失问题:
方式一:用箭头函数包裹错误处理方法
public getPosts(page: number, pageSize: number): Observable<GetPostsResponse> { const url = `${this.myAppUrl}${this.myApiUrl}all?page=${page}&pageSize=${pageSize}`; console.log("GetPosts:" + url); return this.http.get<GetPostsResponse>(url) .pipe( retry(1), // 箭头函数保留当前this上下文 catchError((error) => this.errorHandler(error)) ); }
方式二:构造函数中绑定方法上下文
export class PostService { constructor(private http: HttpClient, @Inject(PLATFORM_ID) private platformId: Object) { this.myAppUrl = environment.appUrl; this.myApiUrl = 'post/'; // 绑定errorHandler的this指向当前实例 this.errorHandler = this.errorHandler.bind(this); } // ... 其他代码 ... }
修复Effects中的Toastr调用
通过PLATFORM_ID判断环境,仅在浏览器端执行Toastr提示:
// 先在Effects构造函数中注入PLATFORM_ID constructor( private actions$: Actions, private store: Store<AppState>, private postService: PostService, private toastr: ToastrService, @Inject(PLATFORM_ID) private platformId: Object ) {} loadPosts$ = createEffect(() => { return this.actions$.pipe( ofType(PostActions.loadPosts), withLatestFrom(this.store), mergeMap(([action, state]) => { console.log("Inside effect loadPosts: "); return this.store.select(getUser).pipe(take(1)).pipe(mergeMap(user => { return this.postService.getPosts(state.post.currentPage + 1, pageSize).pipe( map(posts => { console.log("After getPosts"); return PostActions.loadPostsSuccess({ pageSize: pageSize, posts }); }), catchError(error => { console.log("Error getPosts"); // 仅在浏览器环境下调用Toastr if(isPlatformBrowser(this.platformId)){ this.toastr.error('Error', 'Loading posts'); } return of(PostActions.loadPostsFailure({ error })); }) ) })); }) ); });
额外检查项
- 确保
HttpClientModule同时在AppModule和AppServerModule的imports数组中导入(两端环境都需要); - 验证服务器端能否访问API地址
http://localhost:5001:如果Universal服务和后端服务端口不同,需确认后端服务已启动,必要时改用相对路径或通过环境变量区分两端API地址。
内容的提问来源于stack exchange,提问作者CHardin
相关产品推荐
相关产品推荐

