在 CloudFront 中动态调整图像大小并立即将它们放在相同 URL 中:AWS CloudFront -> S3 -> Lambda -> CloudFront

Resize images on the fly in CloudFront and get them in the same URL instantly: AWS CloudFront -> S3 -> Lambda -> CloudFront

TLDR: 我们必须通过为来自 Lambda 函数的响应创建新的缓存行为来欺骗 CloudFront 307 重定向缓存。

您不会相信我们离实现这一目标有多近。我们在最后一步卡得很厉害。

商业案例:

我们的应用程序将图像存储在 S3 中,并使用 CloudFront 为它们提供服务,以避免全球范围内的任何地理减速。 现在,我们想要真正灵活地设计并能够直接在 CouldFront URL 中请求新的图像尺寸! 每个新的图像尺寸都将按需创建,然后存储在 S3 中,因此第二次请求它将是 服务非常快,因为它将存在于 S3 中,也将缓存在 CloudFront 中。

假设用户上传了图片chucknorris.jpg。 只有原始图像会存储在 S3 中,并会像这样在我们的页面上提供服务:

//xxxxx.cloudfront.net/chucknorris.jpg

我们计算出现在需要显示 200x200 像素的缩略图。 因此我们将图像 src 放在我们的模板中:

//xxxxx.cloudfront.net/chucknorris-200x200.jpg

当请求这个新大小时,亚马逊网络服务必须在同一个桶中使用请求的密钥即时提供它。 这样图片会直接加载到CloudFront的同一个URL中。

我画了一幅丑陋的图,其中包含架构概述和我们在 AWS 中如何执行此操作的工作流程:

以下是 Python Lambda 的结束方式:

return {
    'statusCode': '301',
    'headers': {'location': redirect_url},
    'body': ''
}

问题:

如果我们将 Lambda 函数重定向到 S3,它的效果非常好。 如果我们重定向到 CloudFront,它将进入重定向循环,因为 CloudFront 缓存 307(以及 301、302 和 303)。 一旦我们的 Lambda 函数重定向到 CloudFront,CloudFront 就会调用 API Getaway URL 而不是从 S3 获取图像:

我想在 CloudFront 的 Behaviors 设置选项卡中创建新的缓存行为。 此行为不应缓存来自 Lambda 或 S3 的响应(不知道内部到底发生了什么),但仍应缓存任何后续请求到这个完全相同的调整大小的图像。 我正在尝试设置路径模式 -\d+x\d+\..+$,在添加“Lambda 函数关联”中添加 Lambda 函数的 ARN 并设置事件类型 Origin Response。 接下来,我将“默认 TTL”设置为 0

但是由于某些错误我无法保存该行为:

我们的方向是对的,还是这个“Lambda函数协会”的理念完全不同?

你走在正确的轨道上……也许……但至少有两个问题。

您在此处配置的 "Lambda Function Association" 称为 Lambda@Edge,目前尚不可用。唯一可以访问它的用户是已申请包含在有限预览中的用户。 "maximum allowed is 0" 错误表示您不是预览参与者。我还没有看到任何关于何时对所有帐户生效的公告。

但即使它可用,它也不会以您似乎期望的方式在这里帮助您,因为我不相信 Origin Response 触发器允许您做任何事情来触发 CloudFront 尝试不同的目的地并遵循重定向。如果您看到与此断言相矛盾的文档,请提请我注意。

但是...Lambda@Edge 可用于在 307 上设置 Cache-Control: no-cache,因此 CloudFront 不会缓存它,但重定向本身仍需要一路返回到浏览器。

另请注意,Lambda@Edge 仅支持 Node,不支持 Python...所以也许这还不是您计划的一部分。从问题中我真的无法判断。

Read about the Lambda@Edge limited preview.

第二个问题:

I am trying to set path pattern -\d+x\d+\..+$

你不能那样做。路径模式是支持 * 通配符的字符串匹配。它们不是正则表达式。不过,您可能会逃脱 /*-*x*.jpg,因为 multiple wildcards appear to be supported.

终于解决了。虽然这不是真正的结构性解决方案,但它确实满足了我们的需要。

首先,感谢迈克尔的回答,我已经使用路径模式来匹配所有媒体类型。其次,缓存行为页面对我来说有点误导:Lambda 关联实际上是针对 Lambda@Edge 的,尽管我在缓存行为的所有工具提示中都没有看到这一点:您所看到的只是 Lambda。此功能无法帮助我们,因为我们不想仅仅因为那个特定问题而使用 Lambda@Edge 扩展我们的 AWS 服务范围。

解决方法如下:
我已经定义了多个缓存行为,我们支持的每种媒体类型都有一个:

对于每个缓存行为,我将 Default TTL 设置为 0

最重要的部分:在 Lambda 函数中,我在将调整后的图像放入 S3 时添加了 Cache-Control header:

s3_resource.Bucket(BUCKET).put_object(Key=new_key, 
                                      Body=edited_image_obj,
                                      CacheControl='max-age=12312312',
                                      ContentType=content_type)

为了验证一切正常,我现在看到新的图像尺寸通过 CloudFront 中的缓存 header 提供: