0

I've images stored on S3 and a lambda function to resize them on the fly. While doing it I add CacheControl: 'max-age=31536000' to the resized images and also add a Cache-Control header:

.then(buffer => {
  // save the resized object to S3 bucket with appropriate object key.
  S3.putObject({
    Body: buffer,
    Bucket: BUCKET,
    ContentType: 'image/jpg',
    CacheControl: 'max-age=31536000',
    Key: `uploads/${key}`,
  })

  // generate a binary response with resized image
  response.status = 200
  response.body = buffer.toString('base64')
  response.bodyEncoding = 'base64'
  response.headers['content-type'] = [{ key: 'Content-Type', value: 'image/jpg' }]
  response.headers['cache-control'] = [{ key: 'Cache-Control', value: 'public, max-age=31536000' }]
  callback(null, response)
})

And if the thumbnail has already been generated, I just do:

if (!response.headers['cache-control']) {
  response.headers['cache-control'] = [{ key: 'Cache-Control', value: 'public, max-age=31536000' }]
}
callback(null, response)

On my Cloudfront distribution, I've the following settings:

  • Cache Based on Selected Request Headers: None
  • Object Caching: Use Origin Cache Headers

The lambda works fine but when I look in the devtools, it seems that Chrome never cache the images. Here is the info I get:

General
  Request URL: https://aws.mydomain.com/478/dd123cd5-1636-47d0-b756-e6c6e9cb28c0/normal/pic.jpg
  Request Method: GET
  Status Code: 200 
  Remote Address: 52.84.31.149:443
  Referrer Policy: no-referrer-when-downgrade
  age: 382

Response Headers
  content-length: 49192
  content-type: image/jpg
  date: Thu, 09 May 2019 20:41:42 GMT
  server: AmazonS3
  status: 200
  via: 1.1 261e801dca9c54ff576f39f96d80ede5.cloudfront.net (CloudFront)
  x-amz-cf-id: ZlheiBoNDuYDeuvZo0jBP6Zjpge5AonPGlCo_N2pHhHdGwV7DorKtA==
  x-amz-id-2: xkDxIB0qDJt5KMeHINq7/gaRII6EDBOsL3SlMuhMwJ84M/lak9E/tcRChv7vvYurD+2hYOT8kSI=
  x-amz-request-id: CAD9AE1E905BB13A
  x-cache: Hit from cloudfront

Request Headers
  :authority: aws.mydomain.com
  :method: GET
  :path: /478/dd123cd5-1636-47d0-b756-e6c6e9cb28c0/normal/pic.jpg
  :scheme: https
  accept: */*
  accept-encoding: gzip, deflate, br
  accept-language: en-US,en;q=0.9
  user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.108 Safari/537.36

Control-Cache is not present and I can't figure this out...

When I invalidate all the images in the distribution, the only change is the value of x-cache: 'Error from cloudfront' on the first load (status 200 and image is loaded ok)

gtournie
  • 4,143
  • 1
  • 21
  • 22
  • This particular reaponse is a CloudFront cache hit, of an object fetched from S3. It isn't a generated response from your Lambda function, and it was cached by CloudFront 382 seconds before you requested it. Start by checking the object in the S3 console for the presence of the `Cache-Control` header. – Michael - sqlbot May 10 '19 at 00:41
  • @Michael-sqlbot I updated my question. I also add cache-control in the headers in case the thumbnail has already been generated. If you mean checking if the Metadata Cache-Control is present in the s3 object, yes it is – gtournie May 10 '19 at 01:19

1 Answers1

2

Ok, so apparently it's not possible to add cache-control headers in an origin-response lambda. You have to do it in a viewer-response lambda. Something like that:

exports.handler = (event, context, callback) => {
  const response = event.Records[0].cf.response;
  if (!response.headers['cache-control']) {
    response.headers['cache-control'] = [{
      key: 'Cache-Control',
      value: 'max-age=31536000'
    }];
  }
  callback(null, response);
};
gtournie
  • 4,143
  • 1
  • 21
  • 22