升级到Angular v14.x版本后,发现刷新页面时会出现闪现(flickering)的情况,查看控制台,发现是重复请求的问题,即:服务端发起请求后,在客户端又重新发起了一次请求。

此问题在刚开始接触Angular Universal时已经踩过坑,彼时是通过引入TransferHttpCacheModuleBrowserTransferStateModuleServerTransferStateModule解决的。然而,后两个module在新版本中却报Deprecated错误:

Deprecated symbol used, consult docs for better alternative

官方文档中也显示:

Deprecated: no longer needed, you can inject the TransferState in an app without providing this module.

因此猜测,大概是要自行实现缓存逻辑了……

至于解决方案,直觉上是通过拦截器方式统一实现,因此,直接修改ApiRequestInterceptor

typescriptCopy code
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
if (httpRequest.method !== 'GET') { return next.handle(httpRequest); } const key: StateKey<string> = makeStateKey<string>(`${httpRequest.url}?${httpRequest.params.toString()}`); if (this.platform.isServer) { return next.handle(httpRequest).pipe( tap((event) => { this.state.set(key, (<HttpResponse<any>>event).body); }) ); } else { const storedResponse = this.state.get<any>(key, null); if (storedResponse) { const response = new HttpResponse({ body: storedResponse, status: 200 }); this.state.remove(key); return of(response); } else { return next.handle(httpRequest); } }
if (httpRequest.method !== 'GET') { return next.handle(httpRequest); } const key: StateKey = makeStateKey(`${httpRequest.url}?${httpRequest.params.toString()}`); if (this.platform.isServer) { return next.handle(httpRequest).pipe( tap((event) => { this.state.set(key, (>event).body); }) ); } else { const storedResponse = this.state.get(key, null); if (storedResponse) { const response = new HttpResponse({ body: storedResponse, status: 200 }); this.state.remove(key); return of(response); } else { return next.handle(httpRequest); } }

完整代码请参见:GitHub

几个注意点:

  1. 缓存只针对GET请求;
  2. 缓存只在服务端设置,客户端只进行读取;
  3. 尤其需要注意的,作为缓存的key需要考虑到请求参数,不能直接取httpRequest.url,否则,不同参数的同一个API客户端将读取错误。