8
votes

Is it possible to configure Amazon CloudFront to only ever cache 200 codes? I want it to never cache 3xx as I want to connect it to an on the fly image processing tool with Lambda that performs a 307 via S3 as described ere https://aws.amazon.com/blogs/compute/resize-images-on-the-fly-with-amazon-s3-aws-lambda-and-amazon-api-gateway/

2

2 Answers

9
votes

There isn't a way to explicitly tell CloudFront to cache only 2XX's and not cache 3XX's unless you can configure the origin to set the Cache-Control header accordingly -- CloudFront considers 2XX and 3XX as "success" and treats them the same. (It has different rules for 4XX and 5XX only, and an obvious exception for a 304 response to a conditional request.)

In the case of S3 redirects, the problem with this is that S3 redirection rules do not allow a Cache-Control header to be set.

However, if you are setting the Cache-Control headers correctly on the objects when you create them in S3 -- as you should be -- then you can probably¹ rely on CloudFront's Default TTL setting to solve the problem entirely, by telling CloudFront that responses lacking a Cache-Control header should not be cached. This would mean setting the Default TTL to 0, and would of course require that the Minimum TTL also be set to 0, since minimum <= default is required.

The Maximum TTL should be left at its default value, since it is used to shorten the CloudFront cache time for objects with a max-age that is larger than Maximum TTL. You don't likely want to shorten the cacheability of 2XX responses.

Assuming browsers behave correctly and do not cache the redirect (which they shouldn't, for 307 or 302), then your issue is resolved, because CloudFront behaves as expected in this configuration -- honoring Cache-Control when it's present, and not caching responses when it's absent.

However, you might have to get more aggressive, if you find that browsers or other downstream caches are holding on to your redirects.

The only way to explicitly add Cache-Control (or other headers) to responses when the origin doesn't provide them would be with Lambda@Edge. The following code, used as an Origin Response² trigger, would add Cache-Control: no-cache, no-store, private (yes, it's a bit redundant) to any 3XX HTTP response received from an origin server. If any Cache-Control header is present on the origin's response, it would be overwritten. Any other response (e.g. 2XX) would not be modified.

'use strict';

// add Cache-Control: no-cache, ... only if response status code is 3XX

exports.handler = (event, context, callback) => {
    const response = event.Records[0].cf.response;

    if (response.status.match(/^30[27]/))
    {
        response.headers['cache-control'] = [{ 
          key:   'Cache-Control', 
          value: 'no-cache, no-store, private' 
        }];
    }

    callback(null, response);
};

With this trigger in place, 2XX responses do not have their headers modified, but 302/307 responses will be modified as shown. This will tell CloudFront and the browser not to cache the response.


¹ probably... is not intended to imply that CloudFront merely might do the right thing. CloudFront behaves exactly as expected. Probably refers to this being the only action needed: You can probably consider this solution sufficient, because probably browsers will not cache the redirect. Browser behavior, as usual, is the wildcard that may require the more aggressive addition of explicit Cache-Control headers to prevent caching of the redirect by the browser.

² Origin Response triggers examine and can modify certain aspects of responses before they are cached (if they are cached) and returned to the viewer. Modifying or adding Cache-Control headers at this point in the flow would prevent the response from being stored in the CloudFront cache, and should prevent browser caching as well.

0
votes

If you look at the CloudFront Distribution Error Pages Tab, you can configure the status code caching

You can ignore Response Page Path and HTTP Response Code in your use case.

Next, on CloudFront Behaviour Make sure Caching is zero if you want to retrieve every time from the origin.

If you are using headers, make sure the Origin Cache-Control Headers has the right caching header values.

enter image description here