我们刚刚迁移到 Amazon AWS。我们目前有一个运行良好的 EC2 实例。它在前端运行 Nginx,在后端运行 Apache。它也运行良好。所有网站都已正确启动,并包含从 EC2 提供的文件的 Cache-Control 标头。
问题出在我们放置的所有静态文件中亚马逊 S3正在通过CloudFront CDN。我们可以正常访问文件(并且 CORS 也没有问题),但显然CloudFront 不提供带有 Cache-Control 标头的文件。我们希望利用浏览器缓存。
在我看来,EC2 实例在这里不起作用,因为静态文件由 S3 + CloudFront 直接提供,请求不会发送到 EC2 中的 Web 服务器。
我彻底迷失了。
问题:1) 在这种情况下,如何设置 Cache-Control?2) 是否可以设置 Cache-Control?从 S3 还是 CloudFront?
注意:我在 Google 上找到了几个页面,您可以在其中为单个对象设置 S3 中的标头。这确实不是一种有效的方法,特别是因为在我的例子中我们讨论的是多个对象。
谢谢!
答案1
我在 Google 上找到了几个页面,您可以在其中为单个对象设置 S3 中的标头。这确实不是一种有效的方法,特别是因为在我的例子中我们讨论的是多个对象。
好吧,无论是否“高效”,它实际上就是这么设计的。
CloudFront 没有添加 Cache-Control:
标头。
CloudFront经过 (并且尊重,除非另有配置)Cache-Control:
原始服务器提供的标头,在本例中为 S3 。
若要获取Cache-Control:
S3 在获取对象时提供的标头,必须在将对象上传到 S3 时提供这些标头,或者通过后续的 put+copy 操作将其添加到对象的元数据中,该操作可用于在 S3 中将对象内部复制到自身,从而修改此过程中的元数据。如果您编辑对象元数据,控制台将在后台执行此操作。
而且(如果您想知道的话)S3 中也没有全局设置来强制存储桶中的所有对象返回这些标头 - 它是每个对象的属性。
更新: Lambda@Edge 是 CloudFront 的一项新功能它允许您在查看器和缓存之间和/或缓存和原点之间针对请求和/或响应触发触发器,并针对 CloudFront 公开的简单请求/响应对象结构运行用 Node.js 编写的代码。
此功能的主要应用之一是操作标题...因此,虽然上述内容仍然准确 - CloudFront 本身不会添加Cache-Control
- 但现在 Lambda 函数可以将它们添加到从 CloudFront 返回的响应中。
此示例仅当响应中Cache-Control: public, max-age=86400
没有标头时才会添加。Cache-Control
在 Origin Response 触发器中使用此代码会导致它在每次 CloudFront 从源获取对象时触发,并在 CloudFront 缓存之前修改响应。
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
if(!response.headers['cache-control'])
{
response.headers['cache-control'] = [{
key: 'Cache-Control',
value: 'public, max-age=86400'
}];
}
callback(null, response);
};
更新(2018-06-20):最近,我向 CloudFront 团队提交了一个功能请求,以允许配置静态来源回复标头作为来源属性,类似于静态要求现在可以添加标题...但有一个转折,允许将每个标题配置为有条件地添加(仅当原点未在响应中提供该标题时)或无条件地添加(添加标题并从原点覆盖标题,如果存在)。
对于功能请求,您通常不会收到任何确认,不知道他们是否真的在考虑实施新功能……或者他们是否已经在开发它……他们只是在完成后才宣布。所以,我不知道这些是否会实现。有一种观点认为,由于此功能已经通过 Lambda@Edge 提供,因此在基本功能中不需要它……但我的反驳是,如果没有执行简单、静态响应头操作的能力,那么基本功能在功能上就不完整,如果这是需要触发器的唯一原因,那么要求 Lambda 触发器是一种不必要的成本,无论是财务上还是增加延迟(尽管这两者都不一定是高昂的成本)。
答案2
自从2021 年 11 月,现在可以在 Cloudfront 中本地完成此操作,而无需使用 Lambda@Edge 函数。