具有行为路径重定向的多个 Cloudfront 源

Multiple Cloudfront Origins with Behavior Path Redirection

我有两个 S3 存储桶用作我的 Cloudfront 源服务器:

example-bucket-1
example-bucket-2

两个桶的内容都存在于这些桶的根目录中。我正在尝试将我的 Cloudfront 分发配置为基于 URL 模式进行路由或重写。例如,这些文件

example-bucket-1/something.jpg
example-bucket-2/something-else.jpg

我想让这些 URL 指向各自的文件

http://example.cloudfront.net/path1/something.jpg
http://example.cloudfront.net/path2/something-else.jpg

我尝试设置与 path1 和 path2 模式匹配的缓存行为,但它不起作用。这些模式是否必须实际存在于 S3 存储桶中?

更新: 原始答案(如下所示)在 2015 年编写时是准确的,并且基于 CloudFront 本身的内置行为是正确的。本来,整个请求路径需要存在于原点。

如果 URI 是 /download/images/cat.png 但源仅期望 /images/cat.png 那么 CloudFront 缓存行为 /download/* 将不会执行您可能假设的操作 - 缓存行为的路径模式仅为用于匹配——匹配的前缀不会被删除。

CloudFront 本身不提供在向源发送请求时从浏览器请求的路径中删除元素的方法。如果指定了原始路径,请求总是在收到时转发,或者在开头带有额外的字符。

但是,2017 年 Lambda@Edge 的引入改变了动态。

Lambda@Edge 允许您在 CloudFront 流程中声明触发器挂钩并编写小型 Javascript 函数来检查和修改传入请求,在检查 CloudFront 缓存(查看器请求)之前或之后检查缓存(原始请求)。这允许您重写请求 URI 中的路径。例如,您可以将来自 /download/images/cat.png 的浏览器的请求路径转换为删除 /download,从而导致将 /images/cat.png.[= 的请求发送到 S3(或自定义来源) 32=]

此选项不会修改实际为请求提供服务的缓存行为,因为这始终基于浏览器请求的路径——但您随后可以修改运行中的路径,以便实际请求的对象位于浏览器请求的路径以外的路径中。当在 Origin Request 触发器中使用时,响应缓存在浏览器请求的路径下,因此后续响应不需要重写——它们可以从缓存中获取——并且触发器不需要触发对于每个请求。

Lambda@Edge 函数的实现非常简单。这是一个示例函数,它会删除第一个路径元素,无论它是什么。

'use strict';

// lambda@edge Origin Request trigger to remove the first path element
// compatible with either Node.js 6.10 or 8.10 Lambda runtime environment

exports.handler = (event, context, callback) => {
    const request = event.Records[0].cf.request;           // extract the request object
    request.uri = request.uri.replace(/^\/[^\/]+\//,'/');  // modify the URI
    return callback(null, request);                        // return control to CloudFront
};

就是这样。在 .replace(/^\/[^\/]+\//,'/') 中,我们将 URI 与匹配前导 / 后跟 1 个或多个不能是 / 的字符,然后再匹配一个 / 的正则表达式进行匹配],并用单个 / 替换整个匹配项——因此路径从 /abc/def/ghi/... 重写为 /def/ghi/...,而不管 abc 的确切值如何。这可以变得更复杂以满足特定要求,而不会显着增加执行时间……但请记住,Lambda@Edge 函数与一个或多个缓存行为相关联,因此您不需要单个函数来处理 所有 个请求通过分配——只有与相关缓存行为的路径模式匹配的请求。

要简单地在浏览器的请求前加上前缀,仍然可以使用源路径设置,如下所述,但要删除或修改路径组件,则需要 Lambda@Edge,如上所述。


原回答.

是的,图案必须存在于原点。

CloudFront 本身可以 prepend 到给定来源的路径,但它目前不具备删除路径元素的能力(没有 Lambda@Edge,因为如上所述)。

如果您的文件位于源的 /secret/files/ 中,您可以在将请求发送到源之前转换路径模式 /files/*,方法是设置 "origin path."

反之则不然。如果文件位于 /files 中,则没有内置方法从路径模式 /download/files/*.

提供这些文件

您可以添加(前缀)但不能删除。

一个相对简单的解决方法是在与 S3 存储桶位于同一区域的 EC2 实例上使用反向代理服务器,将 CloudFront 指向代理,并将代理指向 S3。代理将在发送到 S3 的途中重写 HTTP 请求,并将生成的响应流式传输回 CloudFront。我使用这样的设置,它的性能从未让我失望过。 (我开发的反向代理软件实际上可以并行或串行检查多个存储桶,并且 return 它收到的第一个无错误响应,给 CloudFront 和请求者)。

或者,如果使用 S3 网站端点作为自定义来源,您可以使用 S3 重定向路由规则 return 重定向到 CloudFront,将浏览器发回并移除未处理的前缀。这将意味着对每个对象的额外请求,增加延迟和成本,但 S3 重定向规则可以设置为仅在请求实际上不匹配存储桶中的文件时触发。这对于从一种层次结构过渡到另一种层次结构很有用。

http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html

http://docs.aws.amazon.com/AmazonS3/latest/dev/HowDoIWebsiteConfiguration.html