Angular 9 Universal SSR在使用HTTP调用的延迟加载路由上失败

时间:2020-04-13 12:39:31

标签: node.js angular angular-universal angular-animations

我有一个Angular 9(v9.0.6)应用程序,可以在其中与Universal(SSR)一起正常工作,当我注意到该应用程序挂载了100%CPU消耗时,在移至PROD之前我正在执行最后一组测试。我分析了错误,结果发现当Angular应用直接加载路由时,这是一个问题,该路由是执行HTTP调用的延迟加载模块。

如果我通过Home(或没有HTTP的其他路由,但即使有home,也加载了另一个延迟加载的模块,具有进行HTTP调用的相同组件)加载角度,则一切正常。我可以导航到所有路线而没有任何问题,APP的魅力十足。但是,如果我直接说在新选项卡中www.mywebsite / lazy-loaded-module,我相信引导过程中有些东西会阻止所有注册或至少HTTPClientModule正确注册,并且然后我失败了。

首先,我在HTTPClientModule中只注册了一次AppModule。我得到的错误是:

(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,该版本修复了缓冲区警告。该应用程序仍然挂起,并且仅在一个模块上发生。其他模块也进行了http调用(相同的标准get,但具有不同的服务)。

**更新3 **

我已找到问题的根本原因。最终它与HTTP无关。发生的是,在我要引用的页面中,我有一个非常简单的角度动画。它是一个三角形,通过标准角度动画应用无限动画会变得更大或更小。为了实现无限效果,我加入了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

1 个答案:

答案 0 :(得分:1)

是的,如果您知道如何让angular知道请求是由SSR服务器发出的,则有更好的方法来实现动画。

就这样。

您可以看到server.ts

有一个注入令牌。

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

现在您需要做的是进入组件并像下面那样注入此令牌。

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

如果basehref不是SSR,则为空;如果通过SSR请求,则为某个字符串值。

现在提供一种仅在basehref为空时执行动画的方法。