【问题标题】:Add content-type for specific file types in Amazon CloudFront?在 Amazon CloudFront 中为特定文件类型添加内容类型?
【发布时间】:2019-03-17 05:08:05
【问题描述】:
我有一个使用 CloudFront 提供服务的 S3 存储桶。我想从中提供一些 JSON 文件。
开箱即用,CF 响应根本不包含此文件类型的任何 Content-Type 标头。该文件只是由浏览器作为任何常规文件下载。但是,我希望它有一个适当的 mime 类型标题:Content-Type: application/json。
我知道,我可以在 S3 中手动为任何单个文件设置自定义标头,但是,是否可以为特定文件扩展名指定一些规则以将特定 HTTP 标头添加到 Amazon CloudFront 中的响应中?
【问题讨论】:
标签:
amazon-web-services
amazon-s3
amazon-cloudfront
【解决方案1】:
如果您无法控制如何将对象上传到您的 S3 存储桶,您可以使用 Lambda@Edge 函数来覆盖响应标头,如下所示:
(这种方法的缺点是它会增加延迟并产生额外的成本)
-
创建将在下一步中附加到您的 lambda 函数角色的 IAM 策略:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "StatementForCloudWatchLogs",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Sid": "StatementForLambdaFunction",
"Effect": "Allow",
"Action": [
"lambda:EnableReplication",
"lambda:GetFunction"
],
"Resource": [
"arn:aws:lambda:us-east-1:{YOUR_ACCOUNT_ID}:function:{FUNCTION_NAME}:{FUNCTION_VERSION}"
]
},
{
"Sid": "StatementForIAMServiceLinkedRoles",
"Effect": "Allow",
"Action": [
"iam:CreateServiceLinkedRole"
],
"Resource": "arn:aws:iam::{YOUR_ACCOUNT_ID}:role/*"
},
{
"Sid": "StatementForCloudFrontDistributions",
"Effect": "Allow",
"Action": [
"cloudfront:CreateDistribution",
"cloudfront:UpdateDistribution"
],
"Resource": "*"
}
]
}
为 lambda 创建一个新的 AWS 服务 IAM 角色,并将您在步骤 1 中创建的策略附加到该角色。在信任关系下,确保两者都有; lambda.amazonaws.com 和 edgelambda.amazonaws.com 作为可信实体。
-
创建您的 lambda 函数,然后发布一个新版本(在 Actions 下)。您必须使用 nodejs6.10 运行时属性创建函数:
'use strict';
exports.handler = (event, context, callback) => {
const response = event.Records[0].cf.response;
if (response.status === '200') {
response.headers['content-type'] = [{
'value': 'application/json', // <-- Your desired content type.
'key': 'Content-Type'
}];
}
callback(null, response);
};
为您的 CloudFront 分配中的 json 文件创建一个新行为(例如,path/to/your/json/*.json)并确保它位于Default (*) 行为之上。
- 在新创建的行为的 Lambda 函数关联 下,选择 Origin Response 事件类型并输入在步骤 3 中创建的 lambda 函数的 ARN。对于例如:
arn:aws:lambda:us-east-1:{YOUR_ACCOUNT_ID}:function:{FUNCTION_NAME}:{FUNCTION_VERSION}。 (注意:您的 lambda 函数必须在美国东部(弗吉尼亚北部)区域创建,并且函数 ARN 必须具有编号版本,而不是 $LATEST 或别名。
- 为您的
path/to/your/json/* 文件创建 CloudFront 失效。
请务必阅读Requirements and Restrictions on Lambda Functions。
另请参阅Lambda Event Structure 了解更多信息。
【解决方案2】:
更新:CloudFront 本身不提供用于操作标头的内置机制,但与 CloudFront 结合使用的 Lambda@Edge 提供了一种机制来创建可以检查和修改原始响应标头的挂钩。它实际上不能检查响应正文,但可以注入静态或启发式衍生的标头。如果内容来自已知/受信任的来源并且内容类型已知,这可能是一种可行的解决方法,但可能不应该用于用户提交的内容,因为不正确的内容类型可能会导致浏览器误解有效负载,并且可能是一个潜在的利用向量。在上传对象时正确设置对象的内容类型可能仍然是更好的解决方案。
这里的原始答案早于 Lambda@Edge,并且指的是 CloudFront 本身的本机功能。
CloudFront 使用源服务器提供的响应标头,无论是 S3 还是自定义源。 CloudFront 不提供重写或添加它们的机制。
解决方案是在最初将对象上传到 S3 时在对象上设置Content-Type。
如果您将文件上传到 S3 并设置了 Content-Type,则在下载对象时将返回相同的值(无论是直接从 S3 还是通过 CloudFront)。否则,如果您不想要 S3 在未指定时分配的默认 Content-Type: binary/octet-stream 标头,则必须在上传后修改对象。