如何通过Lambda Edge在CloudFront源请求中设置S3存储桶路径
解决Lambda@Edge修改S3静态网站源路径的问题
问题分析
你的核心需求是将原始请求中的网站URL(对应S3桶根目录下的文件夹名称)作为路径前缀,转发到S3静态网站托管源。之前的尝试失败是因为对Lambda@Edge修改源请求的逻辑理解有误,尤其是针对S3静态网站源(而非S3 REST API源)的格式要求。
正确解决方案
Lambda@Edge在**源请求(Origin Request)**阶段修改请求时,需要正确调整origin.custom.path和request.uri两个字段,确保符合S3静态网站托管的路径规则:
场景1:从请求URI中提取网站URL
如果用户通过CloudFront路径访问(例如https://your-cf-domain.com/example.com/page.html),可以从URI中拆分出网站URL作为S3路径前缀:
exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const origin = request.origin.custom; // 拆分URI,提取第一个部分作为网站URL(即S3文件夹名称) const uriSegments = request.uri.split('/').filter(seg => seg); if (!uriSegments.length) { // 处理根路径请求,可根据需求调整默认行为 callback(null, request); return; } const websiteFolder = uriSegments[0]; // 设置源路径:必须以"/"开头 origin.path = `/${websiteFolder}`; // 调整URI为剩余的资源路径,空路径默认指向index.html uriSegments.shift(); request.uri = uriSegments.length ? `/${uriSegments.join('/')}` : '/index.html'; callback(null, request); };
场景2:从Host头提取网站URL
如果用户通过自定义域名(网站URL)直接访问(例如https://example.com/page.html),则从Host头中获取网站URL作为S3路径前缀:
exports.handler = (event, context, callback) => { const request = event.Records[0].cf.request; const origin = request.origin.custom; // 从Host头获取网站URL const websiteFolder = request.headers.host[0].value; // 设置源路径:必须以"/"开头 origin.path = `/${websiteFolder}`; // 根路径请求默认指向index.html if (request.uri === '/') { request.uri = '/index.html'; } callback(null, request); };
为什么之前的尝试失败
- 修改
querystring或uri:直接修改这两个字段会导致CloudFront向S3发送错误的请求格式(例如把网站URL当成查询参数或错误的资源路径),S3无法识别对应的文件夹,因此返回"The specified bucket does not exist"。 - 修改
origin.custom.path格式错误:S3静态网站源要求path必须以/开头,且不能包含非法字符(如冒号、多斜杠等),格式不符合要求时会返回"Invalid path"。 - 追加到
domainName:域名字段仅允许合法的域名格式,不能包含路径部分,因此拼接路径后的域名会被判定为无效,返回"Invalid domainName"。
注意事项
- 确保S3桶的文件夹名称与网站URL完全一致(区分大小写)。
- Lambda@Edge函数必须部署到
us-east-1区域,并关联到CloudFront分发的源请求触发事件。 - 验证S3桶权限,确保CloudFront可以访问目标文件夹下的资源。
- 测试时可通过CloudFront日志查看修改后的请求路径是否符合预期。
内容的提问来源于stack exchange,提问作者Kameron Dawson
相关产品推荐
相关产品推荐

