服务器不会等到 http 调用完成后再渲染 - angular 4 服务器端渲染 [英] Server does not wait till http call completes before rendering - angular 4 server side rendering

查看:22
本文介绍了服务器不会等到 http 调用完成后再渲染 - angular 4 服务器端渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了 angular Universal,并且能够通过服务器端渲染来渲染 html 的静态部分.我面临的问题是,正在调用 API 并且服务器正在渲染 html,而无需等待 http 调用完成.因此,我的模板依赖于从 api 调用获得的数据的部分不会在服务器上呈现.

I have gone ahead and implemented angular universal and able to render static part of html via server side rendering. Issue that I face is, API calls are being made and server is rendering the html without waiting for the http call to complete. So, part where my template is dependent on data obtained from api call is not being rendered on server.

更多信息:

我在节点服务器中使用身份验证,仅当用户通过身份验证并在响应时设置 cookie 时才为索引 html 提供服务.

I use authentication in node server which serve the index html only if the user is authenticated and sets the cookie on response.

每当我从 angular 进行 API 调用时,我也会将 cookie 作为标头发送,因为相关服务也会使用令牌验证用户.对于服务器端渲染,由于 cookie 在服务器级别不可用,我已成功注入请求并为 API 调用选择 cookie.所以,API 调用是成功的,但服务器不会等待承诺解决.

Whenever I make an API call from angular, I also send the cookie as header as the dependent services also validates user with the token. For server side rendering, as the cookie will not be available at server level, I have successfully injected request and pick the cookie for the API call. So, API calls are successful but server is not waiting to render till the promise resolves.

我尝试过但没有成功的步骤:

Steps that I have tried with no success:

我已按照此评论中的建议更改了我的区域版本 https://github.com/angular/universal-starter/issues/181#issuecomment-250177280

I have changed my zone version as suggested in this comment https://github.com/angular/universal-starter/issues/181#issuecomment-250177280

如果需要更多信息,请告诉我.

Please let me know if any further info is required.

指导我使用涉及 http 调用的 angular 通用样板会帮助我.

Directing me to a angular universal boilerplate which has http calls involved would help me.

推荐答案

我已经创建了一个使用 进行异步 API 调用的服务muradm 代码.

I 've created a service for doing the async API calls using muradm code.

要点链接.

import { Injectable } from '@angular/core';
import { Observable, Observer, Subscription } from 'rxjs';



@Injectable({
  providedIn: 'root'
})
export class AsyncApiCallHelperService {

  taskProcessor: MyAsyncTaskProcessor;
  constructor() {
    this.taskProcessor = new MyAsyncTaskProcessor();
  }

  doTask<T>(promise: Promise<T>) {
    return <Observable<T>> this.taskProcessor.doTask(promise);
  }
}

declare const Zone: any;

export abstract class ZoneMacroTaskWrapper<S, R> {
  wrap(request: S): Observable<R> {
    return new Observable((observer: Observer<R>) => {
      let task;
      let scheduled = false;
      let sub: Subscription|null = null;
      let savedResult: any = null;
      let savedError: any = null;

      // tslint:disable-next-line:no-shadowed-variable
      const scheduleTask = (_task: any) => {
        task = _task;
        scheduled = true;

        const delegate = this.delegate(request);
        sub = delegate.subscribe(
            res => savedResult = res,
            err => {
              if (!scheduled) {
                throw new Error(
                    'An http observable was completed twice. This shouldn\'t happen, please file a bug.');
              }
              savedError = err;
              scheduled = false;
              task.invoke();
            },
            () => {
              if (!scheduled) {
                throw new Error(
                    'An http observable was completed twice. This shouldn\'t happen, please file a bug.');
              }
              scheduled = false;
              task.invoke();
            });
      };

      // tslint:disable-next-line:no-shadowed-variable
      const cancelTask = (_task: any) => {
        if (!scheduled) {
          return;
        }
        scheduled = false;
        if (sub) {
          sub.unsubscribe();
          sub = null;
        }
      };

      const onComplete = () => {
        if (savedError !== null) {
          observer.error(savedError);
        } else {
          observer.next(savedResult);
          observer.complete();
        }
      };

      // MockBackend for Http is synchronous, which means that if scheduleTask is by
      // scheduleMacroTask, the request will hit MockBackend and the response will be
      // sent, causing task.invoke() to be called.
      const _task = Zone.current.scheduleMacroTask(
          'ZoneMacroTaskWrapper.subscribe', onComplete, {}, () => null, cancelTask);
      scheduleTask(_task);

      return () => {
        if (scheduled && task) {
          task.zone.cancelTask(task);
          scheduled = false;
        }
        if (sub) {
          sub.unsubscribe();
          sub = null;
        }
      };
    });
  }

  protected abstract delegate(request: S): Observable<R>;
}

export class MyAsyncTaskProcessor extends
    ZoneMacroTaskWrapper<Promise<any>, any> {

  constructor() { super(); }

  // your public task invocation method signature
  doTask(request: Promise<any>): Observable<any> {
    // call via ZoneMacroTaskWrapper
    return this.wrap(request);
  }

  // delegated raw implementation that will be called by ZoneMacroTaskWrapper
  protected delegate(request: Promise<any>): Observable<any> {
    return new Observable<any>((observer: Observer<any>) => {
      // calling observer.next / complete / error
      request
      .then(result => {
        observer.next(result);
        observer.complete();
      }).catch(error => observer.error(error));
    });
  }
}

我希望这对某人有所帮助.

I hope this helps someone.

这篇关于服务器不会等到 http 调用完成后再渲染 - angular 4 服务器端渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆