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

配置AWS CloudFront与Lambda Function URL Origin实现CORS响应

问题描述

创建以Lambda Function URL为源的AWS CloudFront分发时遇到以下问题:

  • 直接通过cURL请求Lambda Function URL,能返回正确的CORS响应头
  • 请求CloudFront URL时,响应中无CORS头返回

已在Lambda Function URL上配置了CORS,相关CDK代码、两种请求的cURL请求及响应如下:

CDK代码

export class Stack extends cdk.Stack {
  constructor( scope: Construct, id: string, props: StackProps ) {
    super( scope, id, props );

    const vpc = cdk.aws_ec2.Vpc.fromLookup( this, 'vpc', { vpcName: props.vpcName } );

    const securityGroup = cdk.aws_ec2.SecurityGroup.fromLookupByName( this, 'lambda-security-group', props.lambdaSecurityGroupName, vpc );

    const lambdaHandler = new cdk.aws_lambda.Function( this, 'lambda-handler', {
      runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2,
      architecture: cdk.aws_lambda.Architecture.ARM_64,
      code: cdk.aws_lambda.Code.fromAsset( '../main.zip' ),
      handler: 'bootstrap',
      vpc: vpc,
      logGroup: new cdk.aws_logs.LogGroup( this, 'api-proxy-log-group', {
        retention: cdk.aws_logs.RetentionDays.ONE_MONTH,
        removalPolicy: cdk.RemovalPolicy.DESTROY,
      } ),
      timeout: cdk.Duration.minutes( 15 ),
      memorySize: props.memorySize,
      retryAttempts: 2,
      securityGroups: [
        securityGroup,
      ],
    } );

    let subDomainName = 'test';

    const domainName = `${subDomainName}.example.com`;

    const funcURL = lambdaHandler.addFunctionUrl( {
      authType: FunctionUrlAuthType.NONE,
      cors: {
        allowedHeaders: [
          'Accept',
          'Authorization',
          'Content-Type',
        ],
        allowedMethods: [
          cdk.aws_lambda.HttpMethod.GET,
          cdk.aws_lambda.HttpMethod.POST,
          cdk.aws_lambda.HttpMethod.PUT,
          cdk.aws_lambda.HttpMethod.HEAD
        ],
        exposedHeaders: [
          'Link',
        ],
        allowedOrigins: props.corsAllowedOrigins,
        allowCredentials: true,
        maxAge: cdk.Duration.seconds( 300 ),
      }
    } );

    const origin = new cdk.aws_cloudfront_origins.FunctionUrlOrigin( funcURL );

    const cloudfrontDistribution = new cdk.aws_cloudfront.Distribution( this, 'cf_distribution', {
      certificate: cdk.aws_certificatemanager.Certificate.fromCertificateArn( this, 'cf_certificate', certArn ),
      priceClass: cdk.aws_cloudfront.PriceClass.PRICE_CLASS_100,
      domainNames: [ domainName ],
      httpVersion: cdk.aws_cloudfront.HttpVersion.HTTP2_AND_3,
      defaultBehavior: {
        origin: origin,
        allowedMethods: cdk.aws_cloudfront.AllowedMethods.ALLOW_ALL,
        viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY,
        originRequestPolicy: cdk.aws_cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
        cachePolicy: cdk.aws_cloudfront.CachePolicy.CACHING_DISABLED
      },
    } );

    new cdk.aws_route53.ARecord( this, 'aliasRecord', {
      zone: cdk.aws_route53.HostedZone.fromLookup( this, "baseZone", {
        domainName: 'example.com',
      } ),
      target: cdk.aws_route53.RecordTarget.fromAlias( new cdk.aws_route53_targets.CloudFrontTarget( cloudfrontDistribution ) ),
      recordName: domainName,
    } );
  }
}

请求Lambda Function URL的cURL请求/响应

curl -i 'https://example.lambda-url.eu-west-2.on.aws' -X 'OPTIONS' -H 'accept: */*' -H 'accept-language: en-GB,en;q=0.9' -H 'access-control-request-headers: authorization' -H 'access-control-request-method: GET' -H 'cache-control: no-cache' -H 'origin: https://test.example.com' -H 'pragma: no-cache' -H 'priority: u=1, i' -H 'referer: https://test.example.com/' -H 'sec-fetch-dest: empty' -H 'sec-fetch-mode: cors' -H 'sec-fetch-site: cross-site' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'

HTTP/1.1 200 OK
Date: Wed, 13 Aug 2025 15:33:40 GMT
Content-Type: application/json
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: https://test.example.com
Access-Control-Allow-Headers: accept,authorization,content-type
Vary: Origin
Access-Control-Allow-Methods: GET,POST,PUT,HEAD,DELETE,PATCH
Access-Control-Max-Age: 300
Access-Control-Allow-Credentials: true

请求CloudFront URL的cURL请求/响应(简化)

curl -i 'https://cloudfront.example.com'   -X 'OPTIONS'   -H 'accept: */*'   -H 'accept-language: en-GB,en;q=0.9'   -H 'access-control-request-headers: authorization'   -H 'access-control-request-method: GET'   -H 'cache-control: no-cache'   -H 'origin: https://test.example.com'   -H 'pragma: no-cache'   -H 'priority: u=1, i'   -H 'referer: https://test.example.com/'   -H 'sec-fetch-dest: empty'   -H 'sec-fetch-mode: cors'   -H 'sec-fetch-site: cross-site' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36'

HTTP/2 200 
content-type: application/json
content-length: 0
date: Wed, 13 Aug 2025 15:33:42 GMT
x-cache: Miss from cloudfront

解决方法

CloudFront不会自动转发源返回的所有响应头,需要显式配置响应头策略来允许CORS相关头传递给客户端。同时要确保请求头能正确传递到源,让Lambda Function URL的CORS配置生效。

步骤1:创建自定义响应头策略

在CDK中创建一个响应头策略,包含所有需要传递的CORS头:

const corsResponsePolicy = new cdk.aws_cloudfront.ResponseHeadersPolicy(this, 'CorsResponsePolicy', {
  corsBehavior: {
    accessControlAllowCredentials: true,
    accessControlAllowHeaders: ['Accept', 'Authorization', 'Content-Type'],
    accessControlAllowMethods: ['GET', 'POST', 'PUT', 'HEAD'],
    accessControlAllowOrigins: props.corsAllowedOrigins,
    accessControlExposeHeaders: ['Link'],
    accessControlMaxAge: cdk.Duration.seconds(300),
    originOverride: false // 使用源返回的CORS头,而非强制覆盖
  }
});

步骤2:将响应头策略关联到CloudFront行为

修改CloudFront Distribution的默认行为,添加responseHeadersPolicy配置:

const cloudfrontDistribution = new cdk.aws_cloudfront.Distribution( this, 'cf_distribution', {
  certificate: cdk.aws_certificatemanager.Certificate.fromCertificateArn( this, 'cf_certificate', certArn ),
  priceClass: cdk.aws_cloudfront.PriceClass.PRICE_CLASS_100,
  domainNames: [ domainName ],
  httpVersion: cdk.aws_cloudfront.HttpVersion.HTTP2_AND_3,
  defaultBehavior: {
    origin: origin,
    allowedMethods: cdk.aws_cloudfront.AllowedMethods.ALLOW_ALL,
    viewerProtocolPolicy: cdk.aws_cloudfront.ViewerProtocolPolicy.HTTPS_ONLY,
    originRequestPolicy: cdk.aws_cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
    cachePolicy: cdk.aws_cloudfront.CachePolicy.CACHING_DISABLED,
    responseHeadersPolicy: corsResponsePolicy // 新增这一行
  },
} );

关键说明

  • originOverride: false 确保CloudFront使用Lambda Function URL返回的CORS头(比如动态的Access-Control-Allow-Origin),而不是强制使用策略中配置的固定值。
  • 确认OriginRequestPolicy包含了Origin、Access-Control-Request-Method、Access-Control-Request-Headers这些预检请求必需的头,ALL_VIEWER_EXCEPT_HOST_HEADER已经包含这些头,无需额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 12:44:52