【问题标题】:Http calls are made twice in angular universalHttp调用在角度通用中进行了两次
【发布时间】:2020-03-04 18:06:12
【问题描述】:

Http调用在初始加载时在angular Universal中进行了两次,我尝试应用传输状态并在我的项目中完成缓存机制,仍然没有任何反应。

if (isPlatformBrowser(this.platformId)) {
 return this.http.get(baseApi + '/blog/slug/' + blogId);
} else {
  const store = this.state.get(MY_DATA, null);
  if (store) {
    return store;
  }
  const myData = this.http.get(baseApi + '/blog/slug/' + blogId);
  this.state.set(MY_DATA, myData);
  return myData;
}

网络通话截图

我是否遗漏了什么,或者有什么我必须包含的内容以避免浏览器调用?提前致谢。

【问题讨论】:

  • 只能缓存有状态转移的数据。看起来您正在尝试缓存一个可观察对象。而你的第一个 if 是错误的,这意味着你总是会在客户端进行 http 调用
  • 真正的问题是,angular ssr 在从浏览器和服务器初始加载时调用 api 两次。这里我必须限制浏览器调用,所以从我最近的研究中我发现使用这种方式我们可以限制浏览器调用。但是没有任何效果,仍然调用了两次。是否有任何解决方案,因为问题仍然在 Github 中打开?
  • 提供网络调用的数据。使用您的浏览器开发工具,转到“网络”选项卡,对通话进行屏幕截图。将屏幕截图添加到问题中。
  • 在我的网络中,我可以看到一个额外的 api 调用。所以这里一个 api 调用是由服务器和另一个客户端进行的,附加的网络调用截图也是如此

标签: angular typescript express server-side-rendering angular-universal


【解决方案1】:

如果您的条件得到验证,它将执行查询

if (isPlatformBrowser(this.platformId)) {
  return this.http.get(baseApi + '/blog/slug/' + blogId);
 } 

在相反的情况下,它进入else 一个除了

const myData = this.http.get(baseApi + '/blog/slug/' + blogId);
  this.state.set(MY_DATA, myData);
  return myData;

始终执行,无论执行的测试如何。

【讨论】:

  • 但是每当页面点击浏览器时,最初仍然会进行两次调用,我是否必须使用任何拦截器文件来全局限制?
【解决方案2】:

就像我在评论中所说,您只能通过状态传输缓存数据。从您的代码来看,您似乎正在尝试缓存一个可观察对象。而你的第一个if是错误的,这意味着你总是会在客户端进行http调用

为了避免调用两次,你可以使用类似下面的代码,这也将防止调用两次服务器端

//Check if cached version exists
const data = this.state.get(MY_DATA, null);
if (data) 
{
    return of(data); //data exists
}

//Data has not been cached yet. Make the call and store result

return this.http.get(baseApi + '/blog/slug/' + blogId)
.pipe(tap(res=> {this.state.set(MY_DATA, res);} );

您还可以使用更多 TransferStateHttpCacheModule,它提供了一个通用拦截器来处理您的所有请求

【讨论】:

  • 我已经尝试过 TransferStateHttpCacheModule 问题仍然存在。我得到了闪烁的故障。
  • TransferStateHttpCacheModule 不起作用
【解决方案3】:

通过安装preboot解决了这个问题,遇到同样问题的朋友可以参考一下: 我们需要等待完整的客户端应用程序使用 preboot 等库引导并运行或缓冲事件。

npm i preboot

在 app.module.ts 的导入下添加以下代码

PrebootModule.withConfig({ appRoot: 'app-root' })

如有必要,还将以下代码添加到 app.module.ts 中的提供程序,

{
provide: APP_INITIALIZER,
  useFactory: function(document: HTMLDocument, platformId: Object): Function {
    return () => {
      if (isPlatformBrowser(platformId)) {
        const dom = ɵgetDOM();
        const styles: any[] = Array.prototype.slice.apply(dom.querySelectorAll(document, `style[ng-transition]`));
        styles.forEach(el => {
          // Remove ng-transition attribute to prevent Angular appInitializerFactory
          // to remove server styles before preboot complete
          el.removeAttribute('ng-transition');
        });
        document.addEventListener('PrebootComplete', () => {
          // After preboot complete, remove the server scripts
          setTimeout(() => styles.forEach(el => dom.remove(el)));
        });
      }
    };
  },
  deps: [DOCUMENT, PLATFORM_ID],
  multi: true  
}

添加这些之后,对我来说,闪烁问题得到了解决。

请参阅官方 angular ssr 链接以获得更清晰的信息:https://angular.io/guide/universal

【讨论】:

  • @gautam 我找不到任何预引导阻止双 http 调用的信息。真的吗?
  • 很抱歉回复晚了,是的。基本上它可以帮助您避免闪烁
  • 不,仍然收到重复的呼叫
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-03-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-24
相关资源
最近更新 更多