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

使用AWS CDK整合API Gateway与Fargate服务时遇参数缺失错误

问题:公网API与私有子网Fargate服务集成时CDK合成报错

执行cdk synthesize --profile=PandaService-Alpha命令时触发以下错误:

/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249
      throw new Error('Either `integrationSubtype` or `integrationUri` must be specified.');
            ^
Error: Either `integrationSubtype` or `integrationUri` must be specified.
    at new HttpIntegration (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:249:13)
    at HttpAlbIntegration._bindToRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/integration.ts:317:26)
    at new HttpRoute (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/route.ts:191:38)
    at /Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:458:14
    at Array.map (<anonymous>)
    at HttpApi.addRoutes (/Users/yangliu/Projects/Panda/PandaApi/node_modules/@aws-cdk/aws-apigatewayv2-alpha/lib/http/api.ts:455:20)
    at ApigatewayStack.addApiRoutes (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:110:22)
    at new ApigatewayStack (/Users/yangliu/Projects/Panda/PandaApi/lib/apigateway-stack.ts:101:10)
    at /Users/yangliu/Projects/Panda/PandaApi/bin/app.ts:17:3

相关代码

import * as CDK from "aws-cdk-lib";

import * as CertificateManager from "aws-cdk-lib/aws-certificatemanager";
import * as Route53 from "aws-cdk-lib/aws-route53";
import * as ApiGatewayV2Alpha from "@aws-cdk/aws-apigatewayv2-alpha";
import * as ApiGatewayV2IntegrationsAlpha from "@aws-cdk/aws-apigatewayv2-integrations-alpha";

import * as ELBv2 from "aws-cdk-lib/aws-elasticloadbalancingv2";
import { Construct } from "constructs";
import { StageInfo } from "../config/stage-config";
import * as EC2 from "aws-cdk-lib/aws-ec2";

export interface ApigatewayStackProps extends CDK.StackProps {
  readonly packageName: string;
  readonly stageInfo: StageInfo;
}

export class ApigatewayStack extends CDK.Stack {
  private readonly coreVpc: EC2.IVpc;
  // Prefix for CDK constrcut ID
  private readonly constructIdPrefix: string;
  private readonly pandaApi: ApiGatewayV2Alpha.HttpApi;
  constructor(scope: Construct, id: string, props: ApigatewayStackProps) {
    super(scope, id, props);

    this.coreVpc = EC2.Vpc.fromLookup(
      this,
      `${props.stageInfo.stageName}VpcLookupId`,
      {
        vpcName: "CoreVpc",
      }
    );

    this.constructIdPrefix = `${props.packageName}-${props.stageInfo.stageName}`;

    const hostedZone: Route53.IHostedZone = Route53.HostedZone.fromLookup(
      this,
      `${this.constructIdPrefix}-HostedZoneLookup`,
      {
        domainName: props.stageInfo.domainName,
      }
    );
    const domainCertificate = new CertificateManager.Certificate(
      this,
      `${this.constructIdPrefix}-pandaApiCertificate`,
      {
        domainName: props.stageInfo.domainName,
        validation:
          CertificateManager.CertificateValidation.fromDns(hostedZone),
      }
    );
    const customDomainName = new ApiGatewayV2Alpha.DomainName(
      this,
      `${this.constructIdPrefix}-ApiGatewayDomainName`,
      {
        certificate: domainCertificate,
        domainName: props.stageInfo.domainName,
      }
    );

    this.pandaApi = new ApiGatewayV2Alpha.HttpApi(
      this,
      `${this.constructIdPrefix}-pandaApi`,
      {
        defaultDomainMapping: {
          domainName: customDomainName,
          //mappingKey: props.pipelineStageInfo.stageName
        },
        corsPreflight: {
          allowOrigins: ["*"],
          allowHeaders: ["*"],
          allowMethods: [
            ApiGatewayV2Alpha.CorsHttpMethod.OPTIONS,
            ApiGatewayV2Alpha.CorsHttpMethod.GET,
            ApiGatewayV2Alpha.CorsHttpMethod.POST,
            ApiGatewayV2Alpha.CorsHttpMethod.PUT,
          ],
          maxAge: CDK.Duration.hours(6),
        },
        //createDefaultStage: false,
        // only allow use custom domain
        disableExecuteApiEndpoint: true
      }
    );

    this.addApiRoutes(props);
  }

  /**
   * Add API routes for multiple services.
   */
  private addApiRoutes(props: ApigatewayStackProps) {
    const PandaServiceIntegration : ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration =
      this.generatePandaServiceIntegration(props);
    this.pandaApi.addRoutes({
      path: "/products",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
    this.pandaApi.addRoutes({
      path: "/store-categories",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
    this.pandaApi.addRoutes({
      path: "/stores",
      methods: [ApiGatewayV2Alpha.HttpMethod.ANY],
      integration: PandaServiceIntegration,
    });
  }

  /**
   *
   * @returns HttpAlbIntegration for PandaService.
   */
  private generatePandaServiceIntegration(props: ApigatewayStackProps) {
    const vpcLink = new ApiGatewayV2Alpha.VpcLink(
      this,
      `${this.constructIdPrefix}-VpcLink`,
      {
        vpc: this.coreVpc,
        subnets: {
          subnetType: EC2.SubnetType.PRIVATE_ISOLATED,
        },
      }
    );

    const PandaServiceAlbSecurityGroup = EC2.SecurityGroup.fromLookupByName(
      this,
      `${this.constructIdPrefix}-PandaServiceAlbSecurityGroupLookup`,
      "PandaServiceAlbSecurityGroup",
      this.coreVpc
    );

    const PandaServiceAlbListener : ELBv2.IApplicationListener =
      ELBv2.ApplicationListener.fromApplicationListenerAttributes(this, `${this.constructIdPrefix}-PandaServiceAlbListenerLookUp`, {
        listenerArn: props.stageInfo.PandaServiceAlbArn,
        securityGroup: PandaServiceAlbSecurityGroup,
      });

    const PandaServiceIntegration: ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration =
      new ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration(
        `${this.constructIdPrefix}-PandaServiceIntegration`,
        PandaServiceAlbListener ,
        {
          method: ApiGatewayV2Alpha.HttpMethod.ANY,
          vpcLink: vpcLink,
          secureServerName: props.stageInfo.domainName,
          parameterMapping: new ApiGatewayV2Alpha.ParameterMapping()
        }
      );

    return PandaServiceIntegration;
  }
}

解决方案

原因分析

报错是因为通过ELBv2.ApplicationListener.fromApplicationListenerAttributes获取的IApplicationListener实例,无法被CDK的alpha版本自动解析出integrationUri或integrationSubtype,导致创建HttpAlbIntegration时缺少必要参数。

修复方法

方法1:升级CDK Alpha包

旧版本的@aws-cdk/aws-apigatewayv2-alpha和@aws-cdk/aws-apigatewayv2-integrations-alpha存在该问题,升级到最新版本可修复:

npm update @aws-cdk/aws-apigatewayv2-alpha @aws-cdk/aws-apigatewayv2-integrations-alpha

方法2:手动指定IntegrationUri

如果无法升级包,需要手动构造integrationUri参数传入HttpAlbIntegration。首先需要从props.stageInfo中传入ALB的ARN(假设添加PandaServiceAlbArn字段),然后构造格式为arn:aws:apigateway:<区域>:elb:path/<ALB-ARN>/<Listener-ARN>的URI:

修改generatePandaServiceIntegration方法中的HttpAlbIntegration创建代码:

const PandaServiceIntegration: ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration =
  new ApiGatewayV2IntegrationsAlpha.HttpAlbIntegration(
    `${this.constructIdPrefix}-PandaServiceIntegration`,
    PandaServiceAlbListener ,
    {
      method: ApiGatewayV2Alpha.HttpMethod.ANY,
      vpcLink: vpcLink,
      secureServerName: props.stageInfo.domainName,
      parameterMapping: new ApiGatewayV2Alpha.ParameterMapping(),
      // 手动指定integrationUri
      integrationUri: `arn:aws:apigateway:${this.region}:elb:path/${props.stageInfo.PandaServiceAlbArn}/${props.stageInfo.PandaServiceListenerArn}`
    }
  );

方法3:直接引用同栈创建的Listener

如果ALB和Listener是在同一CDK应用的其他栈中创建的,不要通过ARN查找,而是通过栈之间的引用传递Listener对象,这样CDK可以自动获取所需的集成参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:37:01