在 angular 通用中进行了两次 Http 调用
Http calls are made twice in angular universal
在初始加载时angular universal 中进行了两次Http 调用,我尝试应用transferstate 并在我的项目中完成了缓存机制,仍然没有任何反应。
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 (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;
始终执行,无论执行的测试如何。
正如我在评论中所说,您只能通过状态传输来缓存数据。从您的代码来看,您似乎正在尝试缓存一个可观察对象。而你的第一个 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,它提供了一个通用拦截器,可以处理您的所有请求
通过安装preboot解决了这个问题,有同样问题的朋友可以按照以下步骤操作:
我们需要等待完整的客户端应用程序 bootstrap 和 运行 或使用 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 link 更清楚:https://angular.io/guide/universal
在初始加载时angular universal 中进行了两次Http 调用,我尝试应用transferstate 并在我的项目中完成了缓存机制,仍然没有任何反应。
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 (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;
始终执行,无论执行的测试如何。
正如我在评论中所说,您只能通过状态传输来缓存数据。从您的代码来看,您似乎正在尝试缓存一个可观察对象。而你的第一个 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,它提供了一个通用拦截器,可以处理您的所有请求
通过安装preboot解决了这个问题,有同样问题的朋友可以按照以下步骤操作: 我们需要等待完整的客户端应用程序 bootstrap 和 运行 或使用 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 link 更清楚:https://angular.io/guide/universal