如何为两种 CloudFront 行为使用不同的错误配置?
How can I use different error configurations for two CloudFront behaviors?
我有一个 CloudFront 分配,其自定义来源指向 /api/*
上的 ALB 和所有其他路径上静态站点的 S3 来源(分配的默认行为)。这服务器存储在 S3 中的 Vue 应用程序和 Fargate 中的 API 运行,由 ALB 进行负载平衡。
在 CloudFront 分配的错误配置中,我有一条规则向 /index.html
发送 404 响应(这是 SPA 所必需的,以便 javascript 路由器可以拾取嵌套路由)。目前,当 API returns 一个 404 响应时,它给出 /index.html
响应,而不是 API 的 404 响应。这是有道理的,但这不是我想要的行为。有没有办法在 /api/*
上获得 API 404 响应,但仅针对默认 S3 Origin/default 行为使用 /index.html
作为 404 响应?
我最初在子域上提供 ALB,所以这不是问题。我试图通过在同一域 (app.mydomain.com
) 上提供 API 和前端站点服务来简化事情,而不是在 mydomain.com
上提供前端服务,而 API 在 api.mydomain.com
,但这已经产生了一个带有错误响应的新错误。
我正在使用 CDK 构建此应用程序,这是我的 CloudFront 分发版代码,它导致了 404 响应问题:
path_patterns = ["/api/*", "/admin/*"]
self.distribution = cloudfront.CloudFrontWebDistribution(
self,
"CloudFrontDistribution",
origin_configs=[
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=alb,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER,
),
behaviors=[
cloudfront.Behavior(
allowed_methods=cloudfront.CloudFrontAllowedMethods.ALL,
path_pattern=path_pattern,
forwarded_values={
"headers": ["*"],
"cookies": {"forward": "all"},
"query_string": True,
},
)
for path_pattern in path_patterns
],
),
cloudfront.SourceConfiguration(
s3_origin_source=cloudfront.S3OriginConfig(
s3_bucket_source=self.static_site_bucket
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD,
)
],
),
],
alias_configuration=cloudfront.AliasConfiguration(
acm_cert_ref=certificate.certificate_arn,
names=[full_domain_name],
),
error_configurations=[
{
"errorCode": 403,
"errorCachingMinTtl": 0,
"responseCode": 200,
"responsePagePath": "/index.html",
},
{
"errorCode": 404,
"errorCachingMinTtl": 0,
"responseCode": 200,
"responsePagePath": "/index.html",
},
],
)
编辑:2020-05-13
我已尝试从 CloudFrontWebDistribution
中删除 error_configuration
并且还在 S3 存储桶上设置了 website_index_document
和 website_error_document
:
self.static_site_bucket = s3.Bucket(
self,
"StaticSiteBucket",
access_control=s3.BucketAccessControl.PUBLIC_READ,
bucket_name=f"{full_app_name}-frontend",
removal_policy=core.RemovalPolicy.DESTROY,
website_index_document="index.html",
website_error_document="index.html",
)
通过此更改,当我希望看到我的 Vue 应用程序提供的 404 页面时,我仍然收到关键错误 404 响应。
在静态站点的 CloudFront 配置中使用 S3 来源是否正确,或者这应该是指向存储桶网站的自定义来源 URL?
我没有为 ALB 和 S3 网站使用自定义来源。以下是 CDK 中描述的所有资源:
from aws_cdk import (
aws_certificatemanager as acm,
aws_s3 as s3,
aws_cloudfront as cloudfront,
aws_route53 as route53,
aws_iam as iam,
aws_route53_targets as targets,
core,
)
class CloudFront(core.Construct):
def __init__(
self,
scope: core.Construct,
id: str,
hosted_zone: route53.IHostedZone,
certificate: acm.ICertificate,
alb: str,
full_domain_name: str,
full_app_name: str,
**kwargs,
) -> None:
super().__init__(scope, id, **kwargs)
self.static_site_bucket = s3.Bucket(
self,
"StaticSiteBucket",
access_control=s3.BucketAccessControl.PUBLIC_READ,
bucket_name=f"{full_app_name}-frontend",
removal_policy=core.RemovalPolicy.DESTROY,
website_index_document="index.html",
website_error_document="index.html",
)
self.policy_statement = iam.PolicyStatement(
actions=["s3:GetObject"],
resources=[f"{self.static_site_bucket.bucket_arn}/*"],
)
self.policy_statement.add_any_principal()
self.static_site_policy_document = iam.PolicyDocument(
statements=[self.policy_statement]
)
self.static_site_bucket.add_to_resource_policy(self.policy_statement)
path_patterns = ["/api/*", "/admin/*", "/flower/*"]
self.distribution = cloudfront.CloudFrontWebDistribution(
self,
"CloudFrontDistribution",
origin_configs=[
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=alb,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER, # noqa
),
behaviors=[
cloudfront.Behavior(
allowed_methods=cloudfront.CloudFrontAllowedMethods.ALL, # noqa
path_pattern=path_pattern,
forwarded_values={
"headers": ["*"],
"cookies": {"forward": "all"},
"query_string": True,
},
)
for path_pattern in path_patterns
],
),
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=self.static_site_bucket.bucket_domain_name,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER, # noqa
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD, # noqa
)
],
),
],
alias_configuration=cloudfront.AliasConfiguration(
acm_cert_ref=certificate.certificate_arn,
names=[full_domain_name],
),
)
route53.ARecord(
self,
"AliasRecord",
target=route53.AddressRecordTarget.from_alias(
targets.CloudFrontTarget(self.distribution)
),
zone=hosted_zone.hosted_zone,
record_name=f"{full_domain_name}.",
)
编辑 2020-05-14
我为自定义来源使用了错误的域名。我尝试了 bucket_regional_domain_name
和 bucket_website_domain_name
,但这些都给了我 my-s3-bucket-name.s3.us-east-1.amazonaws.com
。这是我用于自定义源配置的设置:
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=f"{self.static_site_bucket.bucket_name}.s3-website-us-east-1.amazonaws.com",
origin_protocol_policy=cloudfront.OriginProtocolPolicy.HTTP_ONLY,
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD,
)
],
),
HTTP_ONLY
很重要,这不适用于 MATCH_VIEWER
。另外,请注意我是如何使用 f 字符串来获取 s3-website
存储桶的正确 URL 的。我仍然不确定这是否是我可以在 CDK 中自动找到的东西。如果我发现更多,我会更新这个。
@briancaffey,很高兴再次为您提供帮助。在 CloudFront 中不可能这样做。或者,我认为以下方法应该有效。
- 删除 CloudFront 中的自定义错误响应
- 在您的 S3 源中配置自定义错误文档。 [ref]
- 将 CloudFront
S3Origin
更改为 CustomOrigin
,并将 S3 网站端点设置为源域名。
我有一个 CloudFront 分配,其自定义来源指向 /api/*
上的 ALB 和所有其他路径上静态站点的 S3 来源(分配的默认行为)。这服务器存储在 S3 中的 Vue 应用程序和 Fargate 中的 API 运行,由 ALB 进行负载平衡。
在 CloudFront 分配的错误配置中,我有一条规则向 /index.html
发送 404 响应(这是 SPA 所必需的,以便 javascript 路由器可以拾取嵌套路由)。目前,当 API returns 一个 404 响应时,它给出 /index.html
响应,而不是 API 的 404 响应。这是有道理的,但这不是我想要的行为。有没有办法在 /api/*
上获得 API 404 响应,但仅针对默认 S3 Origin/default 行为使用 /index.html
作为 404 响应?
我最初在子域上提供 ALB,所以这不是问题。我试图通过在同一域 (app.mydomain.com
) 上提供 API 和前端站点服务来简化事情,而不是在 mydomain.com
上提供前端服务,而 API 在 api.mydomain.com
,但这已经产生了一个带有错误响应的新错误。
我正在使用 CDK 构建此应用程序,这是我的 CloudFront 分发版代码,它导致了 404 响应问题:
path_patterns = ["/api/*", "/admin/*"]
self.distribution = cloudfront.CloudFrontWebDistribution(
self,
"CloudFrontDistribution",
origin_configs=[
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=alb,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER,
),
behaviors=[
cloudfront.Behavior(
allowed_methods=cloudfront.CloudFrontAllowedMethods.ALL,
path_pattern=path_pattern,
forwarded_values={
"headers": ["*"],
"cookies": {"forward": "all"},
"query_string": True,
},
)
for path_pattern in path_patterns
],
),
cloudfront.SourceConfiguration(
s3_origin_source=cloudfront.S3OriginConfig(
s3_bucket_source=self.static_site_bucket
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD,
)
],
),
],
alias_configuration=cloudfront.AliasConfiguration(
acm_cert_ref=certificate.certificate_arn,
names=[full_domain_name],
),
error_configurations=[
{
"errorCode": 403,
"errorCachingMinTtl": 0,
"responseCode": 200,
"responsePagePath": "/index.html",
},
{
"errorCode": 404,
"errorCachingMinTtl": 0,
"responseCode": 200,
"responsePagePath": "/index.html",
},
],
)
编辑:2020-05-13
我已尝试从 CloudFrontWebDistribution
中删除 error_configuration
并且还在 S3 存储桶上设置了 website_index_document
和 website_error_document
:
self.static_site_bucket = s3.Bucket(
self,
"StaticSiteBucket",
access_control=s3.BucketAccessControl.PUBLIC_READ,
bucket_name=f"{full_app_name}-frontend",
removal_policy=core.RemovalPolicy.DESTROY,
website_index_document="index.html",
website_error_document="index.html",
)
通过此更改,当我希望看到我的 Vue 应用程序提供的 404 页面时,我仍然收到关键错误 404 响应。
在静态站点的 CloudFront 配置中使用 S3 来源是否正确,或者这应该是指向存储桶网站的自定义来源 URL?
我没有为 ALB 和 S3 网站使用自定义来源。以下是 CDK 中描述的所有资源:
from aws_cdk import (
aws_certificatemanager as acm,
aws_s3 as s3,
aws_cloudfront as cloudfront,
aws_route53 as route53,
aws_iam as iam,
aws_route53_targets as targets,
core,
)
class CloudFront(core.Construct):
def __init__(
self,
scope: core.Construct,
id: str,
hosted_zone: route53.IHostedZone,
certificate: acm.ICertificate,
alb: str,
full_domain_name: str,
full_app_name: str,
**kwargs,
) -> None:
super().__init__(scope, id, **kwargs)
self.static_site_bucket = s3.Bucket(
self,
"StaticSiteBucket",
access_control=s3.BucketAccessControl.PUBLIC_READ,
bucket_name=f"{full_app_name}-frontend",
removal_policy=core.RemovalPolicy.DESTROY,
website_index_document="index.html",
website_error_document="index.html",
)
self.policy_statement = iam.PolicyStatement(
actions=["s3:GetObject"],
resources=[f"{self.static_site_bucket.bucket_arn}/*"],
)
self.policy_statement.add_any_principal()
self.static_site_policy_document = iam.PolicyDocument(
statements=[self.policy_statement]
)
self.static_site_bucket.add_to_resource_policy(self.policy_statement)
path_patterns = ["/api/*", "/admin/*", "/flower/*"]
self.distribution = cloudfront.CloudFrontWebDistribution(
self,
"CloudFrontDistribution",
origin_configs=[
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=alb,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER, # noqa
),
behaviors=[
cloudfront.Behavior(
allowed_methods=cloudfront.CloudFrontAllowedMethods.ALL, # noqa
path_pattern=path_pattern,
forwarded_values={
"headers": ["*"],
"cookies": {"forward": "all"},
"query_string": True,
},
)
for path_pattern in path_patterns
],
),
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=self.static_site_bucket.bucket_domain_name,
origin_protocol_policy=cloudfront.OriginProtocolPolicy.MATCH_VIEWER, # noqa
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD, # noqa
)
],
),
],
alias_configuration=cloudfront.AliasConfiguration(
acm_cert_ref=certificate.certificate_arn,
names=[full_domain_name],
),
)
route53.ARecord(
self,
"AliasRecord",
target=route53.AddressRecordTarget.from_alias(
targets.CloudFrontTarget(self.distribution)
),
zone=hosted_zone.hosted_zone,
record_name=f"{full_domain_name}.",
)
编辑 2020-05-14
我为自定义来源使用了错误的域名。我尝试了 bucket_regional_domain_name
和 bucket_website_domain_name
,但这些都给了我 my-s3-bucket-name.s3.us-east-1.amazonaws.com
。这是我用于自定义源配置的设置:
cloudfront.SourceConfiguration(
custom_origin_source=cloudfront.CustomOriginConfig(
domain_name=f"{self.static_site_bucket.bucket_name}.s3-website-us-east-1.amazonaws.com",
origin_protocol_policy=cloudfront.OriginProtocolPolicy.HTTP_ONLY,
),
behaviors=[
cloudfront.Behavior(
is_default_behavior=True,
cached_methods=cloudfront.CloudFrontAllowedMethods.GET_HEAD,
)
],
),
HTTP_ONLY
很重要,这不适用于 MATCH_VIEWER
。另外,请注意我是如何使用 f 字符串来获取 s3-website
存储桶的正确 URL 的。我仍然不确定这是否是我可以在 CDK 中自动找到的东西。如果我发现更多,我会更新这个。
@briancaffey,很高兴再次为您提供帮助。在 CloudFront 中不可能这样做。或者,我认为以下方法应该有效。
- 删除 CloudFront 中的自定义错误响应
- 在您的 S3 源中配置自定义错误文档。 [ref]
- 将 CloudFront
S3Origin
更改为CustomOrigin
,并将 S3 网站端点设置为源域名。