Overview

Redirection management is a common requirement on websites, often used to redirect non existing URLs (e.g. expired campaigns or following a website structure change), or to localize content based on country. Redirections can be managed at the origin, or at the CDN. Managing redirections at the CDN level could reduce the load on the origin, and reduce the response times. In some cases, such as with static hosting (e.g. S3), redirections can not be managed on the origin. Redirections on CloudFront is managed using its edge functions capabilities.

Architectural decisions

Redirections can be implemented in different ways using edge functions, depending on your requirements. To design the best implementation for your business, consider the following questions

  • How frequently do you update your redirection logic? Heavy usage of redirections in parallel by different teams, requires a more sophisticated implementation compared to simpler, occasional A/B testing.
  • How many redirection rules do you have in your logic? The size of the redirections database is a factor to be considered when evaluating different storage options.
  • Are redirections static or dynamic (e.g. varies based on user country or device capabilities)? When it's dynamic, redirection logic should be executed in a context where all necessary parameters are available to vary the response.
  • Do you rewrite the URL transparently to the user, or send a 3xx Redirection?


To learn about some of the implementations of redirections using CloudFront's edge functions, consider this hands-on this workshop. In the following section, we will share two common implementations of Redirection Management using CloudFront.

How to run HTTP Redirects on AWS CloudFront

Common use cases

Static HTTP redirections

If you are looking to implement HTTP redirections with few rules that rarely change change, configure a CloudFront Function on the viewer request event with redirections logic embedded in the function code. When the redirection logic evolves, you can update the function code, and the new logic will be applied to users within seconds.

For example, the following CloudFront function, configured on viewer request event, sends a 3xx HTTP response to users from selected countries (Spain and UAE) to redirect them to the local version of a Single Page Application (e.g. https://example.com/ -> https://example.com/es/). For this to work, you need to include the cloudfront-viewer-country header in the Origin Request Policy. It instructs CloudFront to make this header available in the CloudFront Function event object, used by your function logic. Note that in this sample code, the user is redirected based on their country unless they specifically ask for a different country version of the SPA.

function handler(event) {
  var request = event.request;
  var headers = request.headers;
  var host = request.headers.host.value;
  var supported_countries = ['ie','ae', 'es']; // countries in which you'd like to serve a localized version of your Single Page Application
  var defaultCountryIndex = 0; // default country index in the support_countries array. here it is 'ie'
  
  if ((supported_countries.includes(request.uri.substring(1,3))) && ((request.uri.substring(3,4) === '/') || (request.uri.length === 3))) {
      // If one of the supported country codes is included in the path (e.g. /es/about) then add index.html when needed to the reauest
      return requestWithIndexHTML(request);
  } else if ((headers['cloudfront-viewer-country']) && (headers['cloudfront-viewer-country'].value.toLowerCase() !== supported_countries[defaultCountryIndex])){
      // Otherwise if the user reauest is coming from one of the supported countries except the default one, then redirect to country specific version (e.g. /about -> /es/about)
      var response = {
          statusCode: 302,
          statusDescription: 'Found',
          headers: { location: { value: `https://${host}/${headers['cloudfront-viewer-country'].value.toLowerCase()}${request.uri}` } },
      };
      return response;      
  } else {
      // Otherwise send rewrite the request to the default country path, add index.html if needed and return
      request.uri = '/'+supported_countries[defaultCountryIndex] + request.uri;
      return requestWithIndexHTML(request);
  }
}

// Add index.html to SPA path when needed
function requestWithIndexHTML(request) {
    if (request.uri.endsWith('/')) {
        request.uri += 'index.html';
    } else if (!request.uri.includes('.')) {
        request.uri += '/index.html';
    }
    return request;
}

Bulk HTTP redirections

CloudFront Function is also capable of supporting larger redirect mappings with the use of CloudFront KeyValueStore, beyond what you can fit within the maximum function size of 10 KB. For example, you could store the URIs you would like to match against in the keys and the redirect URLs in the value. The URI available in the event object of the viewer request can be evaluated for a matching URI and if one exists in the keys, your function can return a 3xx redirection with the associated value.

Using KeyValueStore also has the benefit of decoupling regularly changing data from your code. The KeyValueStore is ideal as a global (every PoP), low-latency read, key value datastore at scale (millions of requests per second).

Advanced requirements for HTTP redirections

A Lambda@Edge based solution is more suitable for advanced redirection requirements, that can't be met by KeyValueStore's maximum size (5 MB) or change velocity limit of few API calls per second. An example scenario is when you have many different marketing teams updating hundreds of thousands of campaign redirections on a daily basis.

 In this architecture, a Lambda@Edge function, configured on origin request event, is executed on every cache miss to check with an external rule storage such as S3 or DynamoDB, what redirection rule to apply. Rules are directly managed in the selected storage, with a possibility to build a simple UI on top of it to facilitate management. An example of this architecture, with an S3 based storage and an authenticated management UI is described in this blog.

Resources

Was this page helpful?