如何将 CloudFront 中的子域映射到 S3 中的同名?

Van*_*yen 6 amazon-s3 subdomain amazon-cloudfront amazon-web-services

我一直在寻找一种方法来执行以下操作,如果有人能启发我,将不胜感激。

例如,在单个 CloudFront 实例中是否可以进行以下映射?

feature-a.domain.com => dev-bucket/feature-a
feature-b.domain.com => dev-bucket/feature-b
staging.domain.com   => dev-bucket/staging
Run Code Online (Sandbox Code Playgroud)

等等..

用例是我希望能够为每个映射到 S3 上存在的存储桶的 git 分支部署尽可能多的环境。这一切有可能吗?

Mic*_*bot 4

是的,这是可能的,但您需要使用 CloudFront 的 Lambda@Edge 增强功能,以便在将请求发送到存储桶之前操作请求参数。

我在这篇官方论坛帖子中描述了一种可能的解决方案。下面包含相同的解决方案。

Lambda@Edge 允许在 CloudFront 处理 HTTP 请求或响应时以编程方式访问它们,本质上是提供触发挂钩。HTTP 事务以 JavaScript 对象的形式呈现,您可以观察和修改该对象,然后将控制权返回给 CloudFront。

对于此应用程序,您需要在 CloudFront 配置中使用托管存储桶端点的网站作为您的原始域名(即不要从下拉列表中选择存储桶 - 使用适当的“s3-website”主机名输入它) )并且您需要将Host标头列入白名单以转发到原点,即使我们实际上不会转发它(我们将读取它,然后与路径一起操作它),并且即使通常将其转发到S3 源无法按预期工作...但我们需要告诉 CloudFront 将其列入白名单,以便可以读取和操作它。

将以下 Lambda 函数配置为源请求触发器。此触发器在检查 CloudFront 缓存并发生缓存未命中之后、请求发送到源服务器 (S3) 之前触发。

'use strict';

// https://serverfault.com/a/930191/153161
// 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)

// set this to what we should remove from the incoming hostname, including the leading dot.

const remove_suffix = '.example.com';

// provide the correct origin hostname here so that we send the correct 
// Host header to the S3 website endpoint
// this is the same value as "origin domain name" in the cloudfront distribution configuration

const origin_hostname = 'example-bucket.s3-website-us-east-1.amazonaws.com';

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
  // we have to do this even if the above if() didn't match
  headers.host[0].value = origin_hostname;

  // return control to CloudFront with the modified request
  return callback(null,request);
};
Run Code Online (Sandbox Code Playgroud)

另请记住将错误缓存最小 TTL设置为 0 ,以避免出现 CloudFront 缓存错误响应。这是与缓存行为设置中的最小/默认/最大 TTL 分开的设置。默认值为 5 分钟,这是有道理的,但如果您没有预料到这种行为,故障排除就会变得复杂。


请注意,Lambda@Edge 函数现在可以使用 v6.10 或v8.10 Node.js 运行时环境。上面的示例最初是为 v6.10 编写的,但与任一运行时兼容,因为在 v8.10 中处理程序有更多选项:它可以使用 async/await,它可以直接返回一个 Promise,或者可以如上所示编写使用回调接口。