You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让使用Zone.JS的Angular Universal等待AWS Lambda SDK调用完成

问题原因

Zone.js 默认仅对 @angular/common/http 依赖的 XHR 调用、Node.js 原生基础异步 API 做了补丁处理,aws-sdk 基于自定义 https Agent 发起的请求逻辑没有被默认纳入 Zone 的任务跟踪范围,因此 Angular Universal 判定应用稳定时不会等待这类请求完成,就会提前返回渲染结果。

解决方案

两种方案均可实现让 Universal 等待 aws-sdk 调用完成:

方案1:通过 NgZone 包裹异步逻辑(推荐,最简)

直接将你的 Lambda 调用逻辑包裹进 Angular 内置的 NgZone 执行上下文,Zone 会自动跟踪内部所有异步任务的状态,等待全部完成后再触发服务端渲染:

import { Injectable, NgZone } from '@angular/core';
import { ApolloLink, Observable } from '@apollo/client/core';
import { AuthService } from '@tma/core';
import AwsLambda from 'aws-sdk/clients/lambda';
import { print } from 'graphql';
import { Agent } from 'https';
import { first } from 'rxjs/operators';

@Injectable({ providedIn: 'root' })
export class ApiLinkLambda extends ApolloLink {
  client = new AwsLambda({
    region: process.env.AWS_REGION,
    httpOptions: {
      agent: new Agent({
        keepAlive: true,
        maxSockets: 50,
        rejectUnauthorized: true,
      }),
    },
  });

  // 注入NgZone
  constructor(private authService: AuthService, private ngZone: NgZone) {
    super(operation => {
      return new Observable(observer => {
        // 将所有异步逻辑包裹到NgZone执行上下文
        this.ngZone.run(() => {
          this.authService.token$
            .pipe(first())
            .toPromise()
            .then(token => {
              return this.client
                .invoke({
                  FunctionName: 'example-graphqlServer',
                  InvocationType: 'RequestResponse',
                  Payload: JSON.stringify({
                    body: {
                      query: print(operation.query),
                      variables: operation.variables,
                    },
                    headers: {
                      Authorization: token,
                    },
                    httpMethod: 'POST',
                    path: '/graphql',
                    requestContext: {
                      requestTimeEpoch: Date.now(),
                    },
                  }),
                })
                .promise()
                .then(result => {
                  const response = JSON.parse(result.Payload!.toString());
                  const body = JSON.parse(response.body);
                  observer.next(body);
                  observer.complete();
                })
                .catch(err => observer.error(err));
            })
            .catch(err => observer.error(err));
        });
      });
    });
  }
}

方案2:手动注册宏任务(兼容性更好)

如果方案1不生效,可以手动向 Zone 注册宏任务,明确告知 Zone 有需要等待的异步任务执行,任务完成后手动触发结束标记即可。该方案和 Angular 服务端 HttpClient 的实现逻辑一致,完全可控:

super(operation => {
  return new Observable(observer => {
    // 手动注册需要等待的宏任务
    const macroTask = Zone.current.scheduleMacroTask(
      'aws-lambda-invoke',
      () => {},
      {},
      // 任务执行逻辑
      () => {
        this.authService.token$
          .pipe(first())
          .toPromise()
          .then(token => this.client.invoke({/* 原有参数保持不变 */}).promise())
          .then(result => {
            const response = JSON.parse(result.Payload!.toString());
            const body = JSON.parse(response.body);
            observer.next(body);
            observer.complete();
            // 标记任务完成
            macroTask.invoke();
          })
          .catch(err => {
            observer.error(err);
            macroTask.invoke();
          });
      },
      () => {}
    );
  });
});

内容的提问来源于stack exchange,提问作者creamcheese

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 14:54:05