在Amazon CloudFront中为特定文件类型添加内容类型?

时间:2016-05-18 18:06:10

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

我有一个S3-bucket,我正在使用CloudFront服务。我想从中提供一些JSON文件。

开箱即用,CF响应根本不包含此文件类型的任何Content-Type标头。该文件只是由浏览器下载为任何常规文件。但是,我希望它有一个合适的mime类型标题:Content-Type: application/json

我知道,我可以在S3中手动为任何单个文件设置自定义标头,但是,是否可以为特定文件扩展名指定一些规则,以便将特定的HTTP标头添加到Amazon CloudFront中的响应中?

2 个答案:

答案 0 :(得分:4)

更新:CloudFront本身不提供用于操纵标头的内置机制,但与CloudFront结合使用的Lambda@Edge提供了一种机制来创建可以检查和修改源响应标头的钩子。它实际上无法检查响应体,但可以注入静态或启发式派生的头。如果内容来自已知/可信来源且内容类型已知,但这可能不适用于用户提交的内容,这可能是一种可行的解决方法,因为不正确的内容类型可能会导致浏览器误解有效负载,可能是一个潜在的漏洞利用载体。正确地,在上传对象时,设置内容类型可能仍然是更好的解决方案。

此处的原始答案早于Lambda @ Edge,并且指的是CloudFront本身的本机功能。

CloudFront使用原始服务器提供的响应标头,无论是S3还是自定义源。 CloudFront不提供重写或添加它们的机制。

解决方案是在最初将对象上传到S3时在对象上设置Content-Type

如果您将文件上传到设置了Content-Type的S3,则下载对象时将返回相同的值(无论是直接从S3还是通过CloudFront)。否则,如果您不想要S3指定的默认Content-Type: binary/octet-stream标题,则必须在上传后修改对象。

答案 1 :(得分:2)

如果您无法控制如何将对象上传到S3存储桶,则可以使用Lambda@Edge函数覆盖响应标头,如下所示:

(此方法的缺点是会增加延迟并产生额外费用)

  1. 创建一个IAM策略,该策略将在下一步中附加到lambda函数的角色:

    {
        "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": "*"
            }
        ]
    }
    
  2. 为lambda创建新的AWS服务IAM角色,并将您在步骤1中创建的策略附加到该角色。在信任关系下,确保您同时拥有这两者; lambda.amazonaws.comedgelambda.amazonaws.com作为可信实体。

  3. 创建lambda函数,然后发布新版本(在操作下)。您必须使用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);
    };
    
  4. 为CloudFront分配中的json文件创建新行为(例如path/to/your/json/*.json),并确保将其置于Default (*)行为之上。

  5. 在新创建的行为的 Lambda函数关联下,选择 Origin Response 事件类型,并输入在步骤3中创建的lambda函数的ARN。例如:arn:aws:lambda:us-east-1:{YOUR_ACCOUNT_ID}:function:{FUNCTION_NAME}:{FUNCTION_VERSION}。 (注意:您的lambda函数必须在美国东部(弗吉尼亚北部)区域创建,函数ARN必须具有编号版本,而不是$LATEST或别名。
  6. path/to/your/json/*文件创建CloudFront失效。
  7. 请务必阅读Requirements and Restrictions on Lambda Functions

    有关其他信息,另请参阅Lambda Event Structure