I have an S3-bucket, that I'm serving using CloudFront. And I want to serve some JSON-files from it.
Out of the box, the CF response doesn't contain any Content-Type
headers at all for this file type. The file is just downloaded by the browser as any regular file. However, I want it to have a proper mime type header: Content-Type: application/json
.
I know, I can set custom header for any single file manually in S3, however, is it possible to specify some rule for specific filename extensions to add specific HTTP headers to the response in Amazon CloudFront?
If you have no control over how objects are being uploaded to your S3 bucket, you could use a Lambda@Edge function to override the response headers as follows:
(The downside to this method is that it increases latency and incurs additional costs)
Create an IAM policy that will be attached to your lambda function's role in the next step:
{
"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": "*"
}
]
}
Create a new AWS service IAM role for lambda and attach the policy you created in step 1 to it. Under Trust relationships, make sure you have both; lambda.amazonaws.com
and edgelambda.amazonaws.com
as trusted entities.
Create your lambda function and then publish a new version (Under Actions). You must create functions with the nodejs6.10 runtime property:
'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);
};
Create a new behavior for json files in your CloudFront distribution (for example, path/to/your/json/*.json
) and make sure it is placed above the Default (*)
behavior.
arn:aws:lambda:us-east-1:{YOUR_ACCOUNT_ID}:function:{FUNCTION_NAME}:{FUNCTION_VERSION}
. (NOTE: Your lambda function must be created in the US East (N. Virginia) region and the function ARN must have a numbered version and not $LATEST
or an alias).path/to/your/json/*
files.Make sure you read the Requirements and Restrictions on Lambda Functions.
See also Lambda Event Structure for additional info.
Update: CloudFront itself does not provide a built-in mechanism for manipulating headers, but Lambda@Edge, used in conjunction with CloudFront, provides a mechanism to create hooks that can examine and modify origin response headers. It can't actually examine the response body, but can inject static or heuristically-derived headers. This is potentially a viable workaround if the content is from a known/trusted source and the content-type is known, but should probably not be used for user-submitted content, since an incorrect content-type could cause a browser to misinterpret the payload, and might be a potential exploit vector. Setting the content-type on the object, correctly, when it is uploaded is probably still the better solution.
The original answer here pre-dates Lambda@Edge and refers to native capabilities of CloudFront itself.
CloudFront uses the response headers provided by the origin server, whether it's S3 or a custom origin. CloudFront does not provide a mechanism to rewrite them or to add them.
The solution is to set the Content-Type
on the object when originally uploading it into S3.
If you upload the file to S3 with Content-Type
set, the same value will be returned when the object is downloaded (whether directly from S3 or through CloudFront). Otherwise, you have to modify objects after upload if you don't want the default Content-Type: binary/octet-stream
header that S3 assigns when you don't specify one.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With