(Angular 6) Angular Universal - 不等待内容 API 调用

Posted

技术标签:

【中文标题】(Angular 6) Angular Universal - 不等待内容 API 调用【英文标题】:(Angular 6) Angular Universal - Not waiting on content API call 【发布时间】:2019-02-15 15:10:33 【问题描述】:

在将 Angular Universal 用于使用动态内容的页面时,无法使 s-s-r 工作。所有其他页面都正常工作,动态页面返回 html,但不包含动态数据。

方法调用:

ngOnInit() 
  const div = this.renderer.createElement('div');
  const texttest = this.renderer.createText('this works');

  this.renderer.appendChild(div, texttest);
  this.renderer.appendChild(this.content.nativeElement, div);

  this.createLinkForCanonicalURL();

  // The HTML never shows, the method works fine.
  this._contentfulService.getBlogPosts().then(posts => 
    this.blogPosts = _.orderBy(posts, ['sys.createdAt'], ['desc']);
  );

服务方式

getBlogPosts(query ? : object): Promise<Entry<any>[]> 
  return this.cdaClient.getEntries(Object.assign(
      content_type: CONFIG.contentTypeIds.blogPosts
    , 
      'fields.private': false
    ))
    .then(res => res.items);

模板:

这永远不会显示在源代码中。

<li class="blog-post" *ngFor="let post of blogPosts">
  <h1>post.fields.title</h1>
</li>

已尝试过入门工具包,但它们无法调用相同的方法。还尝试了 render2 注入和解析器服务来测试加载前获取数据。

似乎没有任何效果?

任何帮助将不胜感激!

编辑

这是我的 server.ts 文件

// These are important and needed before anything else
import 'zone.js/dist/zone-node';
import 'reflect-metadata';

import  enableProdMode  from '@angular/core';
import * as express from 'express';
import  join  from 'path';

// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express server
const app = express();

const PORT = process.env.PORT || 8080;
const DIST_FOLDER = join(process.cwd(), 'dist');

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const  AppServerModuleNgFactory, LAZY_MODULE_MAP  = 
require('./dist/server/main');

// Express Engine
import  ngExpressEngine  from '@nguniversal/express-engine';
// Import module map for lazy loading
import  provideModuleMap  from '@nguniversal/module-map-ngfactory-loader';

app.engine('html', ngExpressEngine(
  bootstrap: AppServerModuleNgFactory,
  providers: [
    provideModuleMap(LAZY_MODULE_MAP)
 ]
));

app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));

// TODO: implement data requests securely
app.get('/api/*', (req, res) => 
  res.status(404).send('data requests are not supported');
);

// Server static files from /browser
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));

// All regular routes use the Universal engine
app.get('*', (req, res) => 
  res.render('index',  req );
);

// Start up the Node server
app.listen(PORT, () => 
  console.log(`Node server listening on http://localhost:$PORT`);
);

和我的应用服务器模块

@NgModule(
bootstrap: [AppComponent],

imports: [
    BrowserModule.withServerTransition( appId: 'app-root' ),

    AppModule,
    ModuleMapLoaderModule,
    ServerModule,
    NoopAnimationsModule,
    ServerTransferStateModule, // comment
]
)
export class AppServerModule  

【问题讨论】:

首先,当您使用 ng serve 启动应用程序时,它是否有效?您是否尝试过其他页面上的 getBlobPosts 方法,您确定它正在返回数据吗?您可以添加 console.log 以查看 s-s-r 上发生的情况 您使用的是哪个版本的 Angular? 方法100%有效,我用的是angular 6 你能在 stackblitz 上重现这个问题吗? 是的,我确实理解了这个问题,但这通常是由于 s-s-r 期间的服务器端错误引起的(不是谈论 API,而是 nodejs 进程执行 s-s-r)。如果服务器端一切正常,我不确定是什么导致了问题。 【参考方案1】:

您需要使用 TransferHttpCacheModule 来等待对 API 的 HTTP 调用,或者使用与 TransferState 一起使用的其他实现,例如 ngx-transfer-http。

等待 3 秒延迟的示例:https://github.com/Angular-RU/angular-universal-starter/blob/master/src/app/transfer-back/transfer-back.component.ts

【讨论】:

如果包含TransferHttpCacheModule的模块尚未安装在应用程序中,请使用npm install @nguniversal/common@x.x.x --save安装它(将x.x.x替换为与您的角度应用程序兼容的版本)【参考方案2】:

似乎 Angular Universal 不会等待异步调用来渲染。

我遇到了同样的问题,最后使用issue 中提到的 ZoneMacroTaskWrapper 使它工作。

这是我制作的service。

【讨论】:

【参考方案3】:

尝试按如下方式编辑您的代码:

async ngOnInit() 
  const div = this.renderer.createElement('div');
  const texttest = this.renderer.createText('this works');

  this.renderer.appendChild(div, texttest);
  this.renderer.appendChild(this.content.nativeElement, div);

  this.createLinkForCanonicalURL();

  const posts = await this._contentfulService.getBlogPosts();
  this.blogPosts = _.orderBy(posts, ['sys.createdAt'], ['desc'])

 

【讨论】:

以上是关于(Angular 6) Angular Universal - 不等待内容 API 调用的主要内容,如果未能解决你的问题,请参考以下文章

Angular 6 中的 AuthHttp(从 Angular2 迁移到 Angular6)

Angular 6 和业力'无法加载“@angular-devkit/build-angular”,它未注册'

Angular JS - 6 - Angular JS 常用指令

如何在 Angular 6 中使用 angular-timelinejs3?

Angular 6:发送经过身份验证的请求

从 Angular 5 升级到 Angular 6,Bootstrap 按钮样式没有间距