如何将站点各动态目录映射到独立S3桶且隐藏S3URL,适配Laravel应用?
最优实现方案
直接采用Amazon CloudFront作为全站入口,搭配CloudFront Functions做路径路由,完全不需要Laravel应用参与,不会暴露S3桶地址,完美满足URL掩码要求,同时支持通过AWS SDK动态更新路由规则。
方案核心逻辑
- 把你的独立域名
example.com绑定到CloudFront分发作为主域名 - 每个需要映射的S3桶都配置为CloudFront的独立源站,不需要给S3桶开启公开访问,仅需要给CloudFront的源访问控制(OAC)授予S3桶的读取权限即可
- 编写CloudFront Function,在
viewer request阶段判断请求的路径前缀,把请求路由到对应的S3源站,也可按需修改转发路径(比如S3桶内的内容存放在根路径,不需要携带/directory前缀的话,可以去掉前缀再转发到对应S3桶)
具体配置步骤
- 准备所有需要用到的S3桶,关闭公有访问权限,为每个桶配置CloudFront OAC访问权限,权限策略参考:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "cloudfront.amazonaws.com" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::你的桶名/*", "Condition": { "StringEquals": { "AWS:SourceArn": "arn:aws:cloudfront::你的AWS账号ID:distribution/你的CloudFront分发ID" } } } ] }
- 在CloudFront分发的「源」配置页,添加所有S3桶作为源,每个源设置唯一的源名称
- 创建CloudFront Function,示例代码如下:
function handler(event) { var request = event.request; // 路径前缀和对应源名称的映射表,可通过AWS SDK动态更新该映射表 var pathToOrigin = { '/directory': 'directory对应的S3源名称', '/random': 'random对应的S3源名称', '/moon': 'moon对应的S3源名称' }; // 匹配最长路径前缀 var matchedOrigin = null; var matchedPrefix = ''; for (var prefix in pathToOrigin) { if (request.uri.startsWith(prefix) && prefix.length > matchedPrefix.length) { matchedOrigin = pathToOrigin[prefix]; matchedPrefix = prefix; } } if (matchedOrigin) { // 绑定到对应的源站 request.origin = { s3: { domainName: matchedOrigin + '.s3.' + event.context.region + '.amazonaws.com', region: event.context.region, authMethod: 'origin-access-control', path: '' } }; // 如果需要去掉前缀再转发到S3,取消注释下一行即可 // request.uri = request.uri.replace(matchedPrefix, ''); request.headers.host = { value: request.origin.s3.domainName }; } // 未匹配到的路径默认走原Laravel源,可将Laravel服务器也配置为CloudFront的源 return request; }
- 把该函数关联到CloudFront分发的viewer request触发事件上,部署生效即可
不推荐S3路由重定向方案的原因
S3自带的路由规则只能返回3xx重定向响应,用户访问时会跳转到S3桶的地址,无法实现你要求的URL掩码效果,完全满足不了需求。
动态配置支持
你可以通过AWS SDK的CloudFront Functions API动态更新函数里的路径映射表,更新后仅需要重新发布函数即可生效,全程不需要修改Laravel应用的任何代码。
内容的提问来源于stack exchange,提问作者Jayson Lane
相关产品推荐
相关产品推荐

