Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AWS CloudFront - forward User-Agent but don't cache against it

I want my origin to be able to see the User-Agent header .e.g: Gecko/20100101 Firefox/62.0 not Amazon CloudFront.

In the Behaviors tab I can whitelist User-Agent header, so it's passed to the origin correctly, however now CloudFront caches content per User-Agent, meaning that user visiting the CloudFront endpoint from different browsers forces CloudFront to go to the origin.

Is there any way to configure CloudFront to pass some headers to the origin, but not necessarily cache against them?

EDIT: I've got similar problem with Accept-Language header. I want to pass it to the origin, however I don't want to cache against it. Assets that I am caching are not Language dependent, however the non-cachable content is dependent on the Accept-Language header.

like image 372
Tomasz Raganowicz Avatar asked Oct 24 '18 08:10

Tomasz Raganowicz


People also ask

How do I disable CloudFront caching?

On your custom origin web server application, add Cache-Control no-cache, no-store, or private directives to the objects that you don't want CloudFront to cache. Or, add Expires directives to the objects that you don't want CloudFront to cache.

Does CloudFront cache get requests?

CloudFront always caches responses to GET and HEAD requests. You can also configure CloudFront to cache responses to OPTIONS requests. CloudFront does not cache responses to requests that use the other methods.

How does CloudFront decide what to cache?

CloudFront caches your objects based on the values in all of the specified headers. CloudFront also forwards the headers that it forwards by default, but it caches your objects based only on the headers that you specify.

Why is CloudFront not caching?

If your CloudFront distribution isn't caching based on the custom values that you set on cache behaviors, then check the origin. Verify whether the origin has any conflicting caching headers.


1 Answers

You can use Lambda@Edge function (https://docs.aws.amazon.com/lambda/latest/dg/lambda-edge.html) assigned to your CloudFront distribution. You would need two functions:

  1. Viewer-Request event handler, that will read User-Agent header and copy it to e.g. X-My-User-Agent. Viewer-Request handler is invoked before the request from the client reaches your Cloudfront Distribution.
  2. Origin-Request event handler, that will read X-My-User-Agent and replace User-Agent. Origin-Request handler is invoked when Cloudfront did not find requested page in its cache and sends the request to the origin.

Please note that you should NOT add User-Agent to Cloudfront whitelist:

You can configure CloudFront to cache objects based on values in the Date and User-Agent headers, but we don't recommend it. These headers have a lot of possible values, and caching based on their values would cause CloudFront to forward significantly more requests to your origin.

Ref: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/RequestAndResponseBehaviorCustomOrigin.html#request-custom-headers-behavior

Example of Viewer-Request handler (Lambda@Edge can be written only in NodeJS or Python, Ref: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-lambda-function-configuration):

'use strict';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const customUserAgentHeaderName = 'X-My-User-Agent';
  const userAgent = headers['user-agent'][0].value;

  headers[customUserAgentHeaderName.toLowerCase()] = [
    {
      key: customUserAgentHeaderName,
      value: userAgent
    }
  ];


  callback(null, request);
};

Example of Origin-Request handler:

'use strict';

exports.handler = (event, context, callback) => {
  const request = event.Records[0].cf.request;
  const headers = request.headers;
  const customUserAgentHeaderName = 'X-My-User-Agent';
  const realUserAgent = headers[customUserAgentHeaderName.toLowerCase()][0].value;

  headers['user-agent'] = [
    {
      key: 'User-Agent',
      value: realUserAgent
    }
  ];


  callback(null, request);
};
like image 160
illagrenan Avatar answered Sep 25 '22 02:09

illagrenan