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

时间:2015-07-22 15:47:40

标签: amazon-web-services amazon-s3 amazon-cloudfront

我有两个S3存储桶作为我的Cloudfront原始服务器:

example-bucket-1
example-bucket-2

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

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

我想让这些网址指向相应的文件

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

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

1 个答案:

答案 0 :(得分:28)

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

如果URI为/download/images/cat.png但原点只需要/images/cat.png,则CloudFront缓存行为/download/*将无法执行您所假设的操作 - 缓存行为的路径模式仅用于匹配 - 匹配的前缀未被删除。

CloudFront本身并没有提供一种方法,可以在将请求发送到源时从浏览器请求的路径中删除元素。如果指定了原始路径,请求将始终在收到时转发,或者在开头添加额外字符。

然而,2017年Lambda@Edge的引入改变了动态。

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

此选项不会修改哪个缓存行为将实际为请求提供服务,因为这始终基于浏览器请求的路径 - 但您可以在运行中修改路径,以便实际请求的对象位于浏览器请求的路径以外的路径。当在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重写为/secret/files/。这可能会变得更加复杂以满足特定要求而不会显着增加执行时间......但请记住Lambda @ Edge函数与一个或多个缓存行为相关联,因此您不需要单个函数来处理通过发布的所有请求 - 只是与相关缓存行为的路径模式匹配的请求。

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

原始答案

是的,模式必须存在于原点。

CloudFront本身可以预先到给定来源的路径,但它目前无法删除路径的元素(没有Lambda @ Edge,如上所述)。 / p>

如果您的文件位于原点的/files/*,则可以通过设置"原始路径将请求发送到原点之前转换路径模式/files。"

相反的情况并非如此。如果文件位于原点/download/files/*,则没有内置方式从路径模式{{1}}提供这些文件。

您可以添加(前缀)但不要带走。

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

或者,如果使用S3网站端点作为自定义源,您可以使用S3重定向路由规则将重定向返回到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