使用Terraform配置CloudFront对接双S3存储桶的路由故障排查
问题分析与解决方案
一、资源路径404错误的原因及修复
1. 核心冲突:Origin Path与路由路径的不匹配
你的CloudFront配置中,resources存储桶的origin设置了origin_path = "/resources",同时对应的ordered_cache_behavior路径模式为"resources*"。这会导致:
- 用户请求
https://dablogga.zenithgamesfoundry.com/resources/mike2_small.png时,CloudFront匹配到该行为后,会自动在请求路径前追加/resources,最终转发到S3的路径变成/resources/resources/mike2_small.png。 - 而你的文件实际存储在resources桶的根目录,S3找不到该路径,因此返回404。
2. 修复步骤
移除Origin Path配置
删除resources origin中的origin_path = "/resources",因为文件并不在桶的resources子目录下:
origin { domain_name = "${aws_s3_bucket.resources.id}.s3-website-${aws_s3_bucket.resources.region}.amazonaws.com" origin_id = "s3-${aws_s3_bucket.resources.id}" # 移除此行:origin_path = "/resources" custom_origin_config { http_port = 80 https_port = 443 origin_keepalive_timeout = 5 origin_protocol_policy = "http-only" origin_read_timeout = 30 origin_ssl_protocols = ["TLSv1.2"] } }
优化路径模式(可选)
将path_pattern改为"resources/*",确保只匹配/resources/开头的路径,避免误匹配类似resources.html这类文件:
ordered_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] path_pattern = "resources/*" # 修改此处 target_origin_id = "s3-${aws_s3_bucket.resources.id}" viewer_protocol_policy = "redirect-to-https" compress = true forwarded_values { query_string = true cookies { forward = "all" } headers = ["Access-Control-Request-Headers", "Access-Control-Request-Method", "Origin"] } }
验证文件存储路径
确认resources桶中的文件直接存储在根目录,而非resources子文件夹。如果文件确实存于子目录,则需保留origin_path并确保请求路径与存储路径一致。
二、基于域名的路由切换实现
可以通过两种方式实现CloudFront基于域名的路由:
方案1:使用Cache Behavior的Host Header条件
利用CloudFront的条件匹配功能,针对特定域名设置专属路由:
- 确保CloudFront的
aliases已包含两个目标域名(当前配置已满足)。 - 添加针对resources域名的ordered_cache_behavior,放在默认behavior之前(CloudFront按顺序匹配行为):
ordered_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] path_pattern = "*" target_origin_id = "s3-${aws_s3_bucket.resources.id}" viewer_protocol_policy = "redirect-to-https" compress = true # 匹配resources域名的Host头 condition { name = "HostHeader" values = ["${var.resources_domain}"] } forwarded_values { query_string = true cookies { forward = "all" } headers = ["Host", "Access-Control-Request-Headers", "Access-Control-Request-Method", "Origin"] } }
方案2:使用Lambda@Edge(更灵活)
创建Lambda@Edge函数在请求阶段根据Host头切换origin:
- 在us-east-1区域创建Lambda函数:
exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const hostHeader = request.headers.host[0].value; if (hostHeader === 'resources.dablogga.zenithgamesfoundry.com') { request.origin.custom.domainName = 'resources.dablogga.zenithgamesfoundry.com.s3-website-ap-southeast-2.amazonaws.com'; request.origin.custom.path = ''; } else { request.origin.custom.domainName = 'dablogga.zenithgamesfoundry.com.s3-website-ap-southeast-2.amazonaws.com'; request.origin.custom.path = ''; } callback(null, request); };
- 将函数关联到CloudFront的
viewer-request事件。
三、额外注意事项
- 403错误通常由S3权限问题导致,当前resources桶的ACL和Public Access Block配置已正确,无需调整。
- CloudFront配置修改后需等待10-15分钟分发生效。
- 可通过CloudFront实时日志或访问日志排查请求转发是否符合预期。
内容的提问来源于stack exchange,提问作者Michael Coxon
相关产品推荐
相关产品推荐

