1
votes

I've done lots of reading on this but none of the solutions I have seen seem to work for IIS websites - most seem to suggest some server-side solution but none of that works for me.

I'm optimising one of our sites, and PageSpeed, YSlow and Lighthouse all complain that images I'm serving from our CloudFront CDN don't have any cache headers. The CDN serves from an S3 bucket.

e.g. https://static.edie.net/webimages/new_new_new.png (expiration not specified)

Crops up as both 'There are static components without a far-future expiration date' and 'Leverage browser caching for the following cacheable resources'

I can't for the life of me work out how to make CloudFront serve a cache header for images like this.

I have set

Cache-Control: max-age=5500000 

on the s3 bucket/file itself, and if you check the file via the bucket: https://devedienet.s3.amazonaws.com/webimages/new_new.png then it has the cache header present.

But that doesn't seem to affect the CloudFront image, which only has these headers:

Age: 12153
Connection: keep-alive
Date: Mon, 22 Oct 2018 11:18:49 GMT
ETag: "940fd4d68428cf3e4f88a45aab4d7157"
Server: AmazonS3
Via: 1.1 4f95eb10423b781564e79d7c85f85795.cloudfront.net (CloudFront)
X-Amz-Cf-Id: TZAWy8U12-ohhe-dwTkCLqXHbJKI7CJqQd21I-lvq-8rloZjTew6aw==
x-amz-meta-s3b-last-modified: 20181017T105350Z
X-Cache: Hit from cloudfront

I've tried adding custom behavours into AWS' Control Panel for the CloudFront distribution:

webimages/*.png
Minimum TTL: 5500000

But again this seems to have no effect.

Note that I invalidated all the images in the folder after adding the new rule above, this but no dice.

Am I missing something or misunderstanding what is required?

2
Invalidate the images again. Age: 12153 means this particular object was cached from S3 12,153 seconds before you made this request. - Michael - sqlbot
Thanks @Michael-sqlbot I'm not sure how invalidating them again will help though? I've done it a few times since I started this and the cache-control header never appears, even if the age is reset that does't help, does it? - Ralpharama
If the object has Cache-Control headers, then invalidating should solve the issue. If Age is resetting, then the invalidation worked. Looking at the response headers from the two URLs, I don't believe your CloudFront distribution is actually pointing at this bucket. I think it's pointing at a different bucket with a copy of the same content. The objects are not the same, even though I got X-Cache: Miss from CloudFront. - Michael - sqlbot
@Michael-sqlbot thanks. Yes, remove the 'dev' from the URL and you'll see the live bucket, I just didn't want to post links to it. Even though the 'cache-control' header is present on the object in the bucket, it isn't present on the object when you fetch it via the CF URL. And that's what I want: is it possible to make specifically the 'cache-control' header be present on the CF version of the file? Either by passthrough from the bucket object headers, or as a rule in the CF setup? Thanks! - Ralpharama
Please provide 2 URLs, one S3 and one CloudFront, that point to exactly the same thing. Your s3 link is new_new.png but your CloudFront link is new_new_new.png. You do not have to do anything to make Cache-Control pass through CloudFront... it always just works... but we need to be, for certain, looking at exactly the same object, and the current state of this question makes this difficult to confirm. - Michael - sqlbot

2 Answers

0
votes

Since 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!

enter image description here

0
votes

I was facing a similar problem, so after doing some reading and experimenting what I figured out is that Cloudfront's Object Caching values of Minimum TTL, Max TTL, Default TTL doesn't add the Cache-Control header explicitly in the Response Headers for the resource if the resource doesn't have one at Server level. Secondlly even if the resource has aCache-control metadata added at S3, it should fall in between MinTTL < s3 Cache < Max TTL . The Object caching values state that for the provided value the resources will be cached for that much time at edge location and no Cache-Control will be added in Response headers for the resource. What I did instead was to create a Lambda function and add it under Lambda associations by updating the Cache Behaviour settings for Viewer Response. Here is my Lambda fn. This added the Cache-Control header in the requested resource.

'use strict';

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;
    const headers = response.headers;
    
const headerCache = 'Cache-Control';


headers[headerCache.toLowerCase()] = [{
    key: headerCache,
    value: 'max-age=1096000'
}];

callback(null, response);

};