配置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
相关产品推荐
相关产品推荐

