AWS CloudFront Leverage browser caching not working - browser-cache

I am trying to set following Origin Custom Headers
Header Name: Cache-Control
Value: max-age=31536000
But it is giving com.amazonaws.services.cloudfront.model.InvalidArgumentException: The parameter HeaderName : Cache-Control is not allowed. (Service: AmazonCloudFront; Status Code: 400; Error Code: InvalidArgument; error.
I tried multiple ways along with setting the Minimum TTL, Default TTL, and Maximum TTL, but no help.

I assume you are trying to get good ratings on gtmetrix page score by leveraging browser caching! If you are serving content from S3 through cloudfront, then you need to add the following headers to objects in S3 while uploading files to S3.
Expires: {some future date}
Bonus: You do not need to specify this header for every object individually. You can upload a bunch of files together on S3, click next, and then on the screen that asks S3 storage class, scroll down and add these headers. And don't forget to click save!

Related

Dynamically override content-type response header in AWS CloudFront

I'm using AWS S3 and CloudFront to distribute content.
My files stored in S3 have binary/octet-stream type but in fact they can be images or documents.
When generating S3 URLs, I can override the response content type with a parameter like this: https://my-bucket.s3.eu-central-1.amazonaws.com/foo/bar?[...]&response-content-type=image/jpeg
Is there a way to do it with CloudFront (with the same S3 bucket as origin)?
I tried adding the same parameter -- it's ignored.
I can create a response headers policy and add a custom header overriding origin, but as far as I can see, it'll be the same for all files whereas I need to control it with a request parameter.

Video.js - HLS => No 'Access-Control-Allow-Origin' header [S3, CloudFront]

I have a problem to play HLS videos using video.js plugin in my application.
I have an S3 storage of HLS videos(.m3u8, .ts) and its connected to cloudfront. Videos are working on safari, but they are not working on chrome properly. They work on chrome just when I hard reload the page(remove cache,cookies,...).
My configurations:
Video.JS:
videojs.Hls.xhr.beforeRequest = function (options) {
options.headers = {
"Access-Control-Allow-Origin": "*",
};
return options;
};
S3 bucket CORS:
[
{
"AllowedHeaders": [
"*"
],
"AllowedMethods": [
"GET",
"PUT",
"POST",
"HEAD"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": [
"ETag",
"Access-Control-Allow-Origin",
"Connection",
"Content-Length"
],
"MaxAgeSeconds": 3000
}
]
CloudFront:
I faced a similar problem. In my case, some files were received successfully but others (in the same dir, uploaded at the same time by the same mechanism) threw CORS error.
After days of investigation, I fixed it (I hope). I leave what I figured out here for future researchers.
The CORS support is implemented in S3 and there is a lot of info on the Internet about how to configure it.
When the CloudFront link is requested AWS checks if there is a requested object in the CloudFront cache. If yes, CloudFront returns it. If not, CloudFront requests it from the origin (S3 in my case), caches it, and returns.
When the S3 link is requested and there is an origin header in the request S3 returns the file with access-control-allow-origin header, otherwise, access-control-allow-origin is not added to response headers.
When CloudFront requests a file from the origin (S3) it can transit request headers (that were sent with file request) to the origin (S3). That's why you have to add the origin header (and any others) to 'Choose which headers to include in the cache key.' In this case, if the request to CloudFront contains the origin header it will also be sent to S3. Otherwise, CloudFront will request a file from the S3 without the origin header, S3 will return a file without the access-control-allow-origin header, and a file without headers will be cached and returned to the browser (CORS error).
headers
Now there are 2 options under cache and origin settings: 'Cache policy and origin request policy (recommended)' and 'Legacy cache settings' (seems like earlier there weren't options and just settings from the 'Legacy cache settings' existed). Under 'Cache policy and origin request policy (recommended)' there are 'Cache policy' and 'Origin request policy - optional' sections. If the predefined recommended policies are set, the origin header (and others) are predefined for 'Origin request policy - optional' but not for 'Cache policy'. To be honest, I don't understand the exact meaning of each but seems like legacy 'Choose which headers to include in the cache key' is now divided into 2 sections. And you have to create a new Cache policy (duplicate of recommended) and add the headers (the same as in CORS-S3Origin policy) if you use 'Cache policy and origin request policy (recommended)' instead of 'Legacy cache settings'.
recomended settings cors-s3origin cachingoptimised
In my case, if the files were requested from a mobile app the first time, the requests didn't have the origin header. That's why S3 returned them without the access-control-allow-origin header and they were cached in CloudFront without headers. All next requests with the origin header (browser always add this header when you make a request from js) failed because of CORS error ("No 'Access-Control-Allow-Origin'...").
There is an ability to add custom headers to requests from CloudFront to S3 (Origins -> Edit particular origin -> Add custom header). If you don't care from where users request your files, you can add the origin header here and set it to any value. In this case, all requests to S3 will have the origin header.
custom header
There are a lot of CloudFront edge locations. Each of them has its own cache. The user will receive files from the nearest one. That's why it's possible that some users receive files successfully, but others get CORS errors.
There is an x-cache header in CloudFront response headers. The value can be either "Miss from cloudfront" (there is no request file in the cache) or "Hit from cloudfront" (the file returned from the cache). So, you can see if your request is the first to a particular edge location (disable browser cache in devtools if you want to try). But sometimes it behaves like randomly) and I don't know why.
Looks like even the same edge location can have different caches for different clients. I don't know what is it based on, but I've tried to experiment with browser, Postman, and curl, and have got the next results (I've tried many times with different files and different ordering - the request from the curl doesn't see the cache created for browser and Postman, and vice versa):
the request from the browser returns "Miss from cloudfront";
the request from the browser returns "Hit from cloudfront";
the request from the Postman returns "Hit from cloudfront";
the request from the curl returns "Miss from cloudfront";
the request from the curl returns "Hit from cloudfront".
As AWS docs are quite poor about this question and support just recommends reading the docs, I'm not sure about part of my conclusions. That's just what I think.

AWS s3 SignatureDoesNotMatch error during get Request through Cloudfront

I have two cloudfront and one s3 bucket and in both cloudfront i have added s3 bucket as a origin. (i am using origin access identity to serve s3 content)
I added same behavior in both cloudfront.
My problem is
I am able to access get s3 using only one cloudfront and its throwing error SignatureDoesNotMatch with other cloudfront.
For example:
https://cloudront1url/images/a.jpg is working but
https://cloudfront2url/images/a.jpg is not working.
Error that i am getting is click here
I got the issue. in behavior i was using "Cache Based on Selected Request Headers" (whitelist option) for s3 origin. I was white listing "host" header. when i choose option "none" in "Cache Based on Selected Request Headers" issue gets resolved.
In my case it was Origin Request Policy in Cloudfront being set to forward all headers which turns out takes your request headers and calculates signature while s3 calculates signature from specific set of headers.
Correct way to use OAI is with CORS-S3Origin request policy or cherry pick selected headers yourself.
I got a hint from this article. I had to edit the behavior, use “Legacy cache settings” and select “All” for “Query strings” (select default “None” for “Headers”, and select default “None” for “Cookies”). After that, the SignatureDoesNotMatch error was gone.
Here is the screenshot of the CloudFront behavior.

Cloudfront Won't Set Expiration Header from S3 Origin

I am using an S3 bucket to store a bunch of product images for a large web site. These images are being served through Cloudfront with the S3 bucket as the origin. I have noticed that Cloudfront does not put an expiration header on the image even though I have set the distribution behavior to customize the cache headers and set a long min, max, and default TTL in Cloudfront.
I understand that I can put an expiration on the S3 object, however this is going to be quite impractical as I have millions of images. I was hoping that cloudfront would do me the honors of adding this header for me, but it does not.
So my question is the only way to get this expiration header to apply it every S3 object, or perhaps I am missing something in Cloudfront that will do it for me?
CloudFront's TTL configuration only controls the amount of time CloudFront keeps the object in the cache.
It doesn't add any headers.
So, yes, you'll need to set these on the objects in S3.
Note that Cache-Control: is usually considered a better choice than Expires:.
A alternative to avoid updating the onjects is to configure a proxy server in EC2 in the same region as the bucket, and let the server add the headers as the responses pass through it.
Request: CloudFront >> Proxy >> S3
Response: S3 >> Proxy >> CloudFront
...for what it's worth.

Removing response headers when accessing images from S3

Can we remove response headers when we are accessing images stored on Amazon S3?
By default it is giving the following headers:
x-amz-id-2:
x-amz-request-id:
Server:
By default it is giving amazon related values for these headers. Is there any way to remove headers?
Not without proxying the requests through some software you control that can strip the headers. Pretty sure Amazon has no user setting for that.