web-dev-qa-db-ja.com

Angular 9遅延ロードされたルートで9ユニバーサルSSRがHTTP呼び出しで失敗する

Angular 9(v9.0.6)アプリがユニバーサル(SSR)で正常に動作していて、アプリケーションが100でハングしていることに気付いたときに、PRODに移行する前に最後のテストセットを実行していました。 %CPU消費率私はエラーを分析し、AngularアプリがHTTP呼び出しを実行する遅延ロードされたモジュールであるルートを直接ロードするときに問題であることがわかりました。

ホームを介してangular=(またはHTTPを使用しない別のルート-しかし、ホームであっても、別の遅延ロードされたモジュールがHTTP呼び出しを行う同じコンポーネントを持っている)をロードすると、正常に動作します。ナビゲートできますすべてのルートに問題なくAPPは魅力のように機能します。私が行ったとしても、新しいタブで直接www.mywebsite/lazy-loaded-moduleと言うと、bootstrapプロセスにより、すべての登録、または少なくともHTTPClientModuleが正しく登録されず、エラーが発生します。

まず、HTTPClientModuleAppModuleを1回だけ登録しました。私が得るエラーは:

(node:17624) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.

CPUが100%になり、アプリケーションがハングします。繰り返しますが、www.my-website.com次に、アプリをナビゲートして/my-lazy-loaded-module

次に別の方法を試しました:遅延ロードされたモジュール内にHTTPClientModuleを含めると(そうすべきではないことがわかります)、CPUの問題と同様に機能しなくなりましたが、別のエラーが発生しました。

ReferenceError: XMLHttpRequest is not defined
    at BrowserXhr.build

これは、SSRを使用して取得し、何もないためレンダリングするコンテンツに影響を与えます。それを行うことができる回避策として、私はこれがどのように扱われるべきか知りたいです。私が実行しているnodeバージョンは次のとおりです:v10.16.2

[〜#〜]更新[〜#〜]

私が行っているHTTP呼び出しについてより多くの可視性を提供するために、これは単なる標準的な呼び出しです。

public getNext = (page: number, pageSize: number): Promise<IEventsPaged> => {
        return this.http.get<IEventsPaged>(`${environment.apiBaseUrl}/events?page=${page}&pageSize=${pageSize})
                        .toPromise()
                        .then(r => r)
                        .catch((error: Response | any) => {
                            return Promise.reject(error);
                        });
    }

更新2

Angular 9.1.1に更新しました。これにより、バッファ警告が修正されます。アプリケーションは依然としてハングし、1つのモジュールでのみ発生します。他のモジュールもhttp呼び出しを行っています(同じ標準のgetですが、別のサービスで)問題なく。

**更新3 **

問題の根本的な原因を発見しました。最終的にはHTTPとは何の関係もありませんでした。起こっていたのは、私が言及しているページにangularアニメーションが非常にシンプルであることです。これは、標準のangularアニメーション。無限の効果を達成するために、animation.doneイベントを使用して、状態を大または小に変更します。さて、そのアニメーションが配置されているルート上のページをハードリフレッシュすると、次のような無限ループになります。

{ element:
   HTMLDivElement {
     parentNode:
      HTMLUnknownElement {
        parentNode: [HTMLDivElement],
        _previousSibling: [HTMLDivElement],
        _nextSibling: [HTMLImageElement],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Circular],
        nodeType: 1,
        ownerDocument: [Object],
        localName: 'app-bottom-angle',
        namespaceURI: 'http://www.w3.org/1999/xhtml',
        prefix: null,
        _tagName: undefined,
        _attrsByQName: [Object],
        _attrsByLName: [Object],
        _attrKeys: [Array],
        __ngContext__: [LComponentView_CalendarIntroductionComponent],
        _classList: [DOMTokenList],
        _nid: 79 },
     _previousSibling: [Circular],
     _nextSibling: [Circular],
     _index: undefined,
     _childNodes: null,
     _firstChild: null,
     nodeType: 1,
     ownerDocument:
      { parentNode: null,
        _previousSibling: [Circular],
        _nextSibling: [Circular],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Object],
        nodeType: 9,
        isHTML: true,
        _address: 'http://localhost:54818/en/calendar',
        readyState: 'loading',
        implementation: [Object],
        ownerDocument: null,
        _contentType: 'text/html',
        doctype: [Object],
        documentElement: [HTMLHtmlElement],
        _templateDocCache: null,
        _nodeIterators: null,
        _nid: 1,
        _nextnid: 152,
        _nodes: [Array],
        byId: [Object],
        modclock: 23,
        _scripting_enabled: true,
        defaultView: [Object],
        _lastModTime: 1 },
     localName: 'div',
     namespaceURI: 'http://www.w3.org/1999/xhtml',
     prefix: null,
     _tagName: undefined,
     _attrsByQName:
      [Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
     _attrsByLName:
      [Object: null prototype] {
        '|_ngcontent-sc33': [Object],
        '|class': [Object],
        '|style': [Object] },
     _attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
     _classList:
      DOMTokenList {
        '0': 'position-absolute',
        '1': 'z-index-plus-1',
        '2': 'bottom-0',
        '3': 'right-0',
        '4': 'left-0',
        '5': 'mb-4',
        '6': 'ng-tns-c33-1',
        '7': 'ng-trigger',
        '8': 'ng-trigger-scale',
        '9': undefined,
        '10': undefined,
        _getString: [Function],
        _setString: [Function],
        _length: 9 },
     __ngContext__:
      LComponentView_BottomAngleComponent [
        [HTMLUnknownElement],
        [TView],
        211,
        [LComponentView_CalendarIntroductionComponent],
        null,
        null,
        [TNode$1],
        [LCleanup],
        [BottomAngleComponent],
        [Object],
        [AnimationRendererFactory],
        [AnimationRenderer],
        null,
        null,
        null,
        [LComponentView_CalendarIntroductionComponent],
        [Circular],
        null,
        0,
        [Circular],
        'big' ],
     _nid: 80,
     _style:
      { _element: [Circular],
        _parsedStyles: [Object],
        _lastParsedText: 'transform: scale(1); transform-style: preserve-3d;',
        _names: [Array] } },
  triggerName: 'scale',
  fromState: 'small',
  toState: 'big',
  phaseName: 'done',
  totalTime: 1200,
  disabled: false,
  _data: 1006 }
{ element:
   HTMLDivElement {
     parentNode:
      HTMLUnknownElement {
        parentNode: [HTMLDivElement],
        _previousSibling: [HTMLDivElement],
        _nextSibling: [HTMLImageElement],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Circular],
        nodeType: 1,
        ownerDocument: [Object],
        localName: 'app-bottom-angle',
        namespaceURI: 'http://www.w3.org/1999/xhtml',
        prefix: null,
        _tagName: undefined,
        _attrsByQName: [Object],
        _attrsByLName: [Object],
        _attrKeys: [Array],
        __ngContext__: [LComponentView_CalendarIntroductionComponent],
        _classList: [DOMTokenList],
        _nid: 79 },
     _previousSibling: [Circular],
     _nextSibling: [Circular],
     _index: undefined,
     _childNodes: null,
     _firstChild: null,
     nodeType: 1,
     ownerDocument:
      { parentNode: null,
        _previousSibling: [Circular],
        _nextSibling: [Circular],
        _index: undefined,
        _childNodes: null,
        _firstChild: [Object],
        nodeType: 9,
        isHTML: true,
        _address: 'http://localhost:54818/en/calendar',
        readyState: 'loading',
        implementation: [Object],
        ownerDocument: null,
        _contentType: 'text/html',
        doctype: [Object],
        documentElement: [HTMLHtmlElement],
        _templateDocCache: null,
        _nodeIterators: null,
        _nid: 1,
        _nextnid: 152,
        _nodes: [Array],
        byId: [Object],
        modclock: 23,
        _scripting_enabled: true,
        defaultView: [Object],
        _lastModTime: 1 },
     localName: 'div',
     namespaceURI: 'http://www.w3.org/1999/xhtml',
     prefix: null,
     _tagName: undefined,
     _attrsByQName:
      [Object: null prototype] { '_ngcontent-sc33': [Object], class: [Object], style: [Object] },
     _attrsByLName:
      [Object: null prototype] {
        '|_ngcontent-sc33': [Object],
        '|class': [Object],
        '|style': [Object] },
     _attrKeys: [ '|_ngcontent-sc33', '|class', '|style' ],
     _classList:
      DOMTokenList {
        '0': 'position-absolute',
        '1': 'z-index-plus-1',
        '2': 'bottom-0',
        '3': 'right-0',
        '4': 'left-0',
        '5': 'mb-4',
        '6': 'ng-tns-c33-1',
        '7': 'ng-trigger',
        '8': 'ng-trigger-scale',
        '9': undefined,
        '10': undefined,
        _getString: [Function],
        _setString: [Function],
        _length: 9 },
     __ngContext__:
      LComponentView_BottomAngleComponent [
        [HTMLUnknownElement],
        [TView],
        211,
        [LComponentView_CalendarIntroductionComponent],
        null,
        null,
        [TNode$1],
        [LCleanup],
        [BottomAngleComponent],
        [Object],
        [AnimationRendererFactory],
        [AnimationRenderer],
        null,
        null,
        null,
        [LComponentView_CalendarIntroductionComponent],
        [Circular],
        null,
        0,
        [Circular],
        'small' ],
     _nid: 80,
     _style:
      { _element: [Circular],
        _parsedStyles: [Object],
        _lastParsedText: 'transform: scale(1.2); transform-style: preserve-3d;',
        _names: [Array] } },
  triggerName: 'scale',
  fromState: 'big',
  toState: 'small',
  phaseName: 'done',
  totalTime: 1200,
  disabled: false,
  _data: 1007 }

そして、アプリケーションがハングします。 Angularアニメーションを使用して無限アニメーションを実現するより良い方法があるかどうか、そしてSSRが脆弱であることを「知る」ことは開発者の責任であるかどうかはわかりません。私は推測します。それらがHTML要素を扱っていると思うなら、それらはすべてそれらの中でisPlatformBrowserを使用すべきであると主張することができます。

2

はい、angularにリクエストがSSRサーバーによって発行されていることを通知する方法を知っている場合、アニメーションを実現するより良い方法があります。

だからここに行く。

あなたはserver.tsを見ることができます

注入される注入トークンがあります。

providers: [
    { provide: APP_BASE_HREF, useValue: req.baseUrl },

今あなたがする必要があるのはコンポーネントに行き、以下のようにこのトークンを注入することです。

constructor(
@Optional() @Inject(APP_BASE_HREF) private basehref: string,

basehrefがSSRでない場合はnullになり、SSRから要求された場合は一部の文字列値になります。

basehrefがnullの場合にのみアニメーションを実行する方法を提供するようになりました。

1
Vipin Jain