CloudFront + Lambda@Edge + S3 可以做到这一点“无服务器”。
Lambda@Edge 是一项 CloudFront 增强功能,它允许将请求和响应的属性表示为简单的 JavaScript 对象并对其进行操作。触发器可以在请求处理期间触发,可以在检查缓存之前(“查看器请求”触发器)或在请求继续到后端(“源服务器”,在本例中为 S3 网站托管端点)之前触发在缓存未命中(“源请求”触发器)之后......或在响应处理期间,在从源接收到响应之后但在考虑将其存储在 CloudFront 缓存中之前(“源响应”触发器),或在完成对浏览器的响应(“查看器响应”触发器)。响应触发器也可以检查原始请求对象。
以下 sn-p 是我最初在 AWS 论坛上的 posted。这是一个原始请求触发器,它将原始主机名与您的模式进行比较(例如,域必须匹配 *.example.com),如果匹配,则主机名前缀 subdomain-here.example.com 是从为子域命名的文件夹中提供的请求。
lol.example.com/cat.jpg -> my-bucket/lol/cat.jpg
funny-pics.example.com/cat.jpg -> my-bucket/funny-pics/cat.jpg
通过这种方式,来自任意多个子域的静态内容都可以从一个存储桶中提供。
为了访问原始传入的 Host 标头,需要将 CloudFront 配置为 whitelist the Host header for forwarding to the origin,即使 Lambda 函数执行的最终结果是在源端实际看到之前修改该值。
代码其实很简单——以下大部分是解释性cmets。
'use strict';
// if the end of incoming Host header matches this string,
// strip this part and prepend the remaining characters onto the request path,
// along with a new leading slash (otherwise, the request will be handled
// with an unmodified path, at the root of the bucket)
const remove_suffix = '.example.com';
// provide the correct origin hostname here so that we send the correct
// Host header to the S3 website endpoint
const origin_hostname = 'example-bucket.s3-website.us-east-2.amazonaws.com'; // see comments, below
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
const host_header = headers.host[0].value;
if(host_header.endsWith(remove_suffix))
{
// prepend '/' + the subdomain onto the existing request path ("uri")
request.uri = '/' + host_header.substring(0,host_header.length - remove_suffix.length) + request.uri;
}
// fix the host header so that S3 understands the request
headers.host[0].value = origin_hostname;
// return control to CloudFront with the modified request
return callback(null,request);
};
请注意,来自 S3 的索引文档和重定向可能还需要 Origin Response 触发器来针对原始请求规范化 Location 标头。这将取决于您使用的 S3 网站功能。但以上是一个说明总体思路的工作示例。
请注意,const origin_hostname 需要设置为 CloudFront 源设置中配置的存储桶的终端节点主机名。在此示例中,存储桶位于 us-east-2 中,并且网站托管功能处于活动状态。