Redirection on CloudFront with Lambda@Edge

Furkan Bayraktar
Rn Engineering

--

Amazon CloudFront together with S3 is one of the simplest and fastest solutions to publish a new website these days. At House of Radon, we use CloudFront + S3 combination a lot with the websites we release. We mainly use React to develop these websites as Single Page Applications.

One of the main problems we had for a while was sharing specific pages with specific metadata on social media. Some well known solutions for this problem on SPA ecosystem are server side rendering or pre-rendering pages before publishing into HTML files for each route you have in the application.

You can then have folders with pre-rendered index.html files in it and serve those when a client hits a specific endpoint. For example, if you have a route at /home/my-page you can create a folder home and another one underneath it named my-page which contains an index.html with specific metadata and same js references as your SPA. You can generate this kind of output with the help of libraries like react-snap or react-snapshot.

The Issue

This was not an issue until we decided to use S3 private buckets and serve it through CloudFront with S3 origin. S3 has the functionality to serve index.html files within folders automatically if you don’t provide it specifically. For example, if you try to reach a route at /home/page, it can serve /home/page/index.html automatically. However, CloudFront does not have this functionality except for the main folder. It can serve /index.html when you hit /, but it can’t serve /home/page/index.html when you hit /home/page.

This behavior does not block us from serving SPAs through CloudFront. In any case, our SPA will redirect internally to correct page. The problem is with sharing and Search Engine Optimization (SEO), more specifically, with metadata. We were still using snapshot tools to generate folder structure and index.html files as well as specific metadata using React Helmet, but we were unable to serve those files.

Solution: Lambda@Edge

Lambda@Edge is a specific version of Lambda where you can attach functions to your CloudFront distributions. These functions replicate through all of the edge locations and run on the edge. It’s limited to Node.js and has some extra limitations compared to original Lambda. You can find those limitations here.

With Lambda@Edge, you can intercept a CloudFront request in 4 different stages. These stages are explained well in the following diagram.

Image Source: Amazon Lambda@Edge Documentation

We decided to intercept origin request, where CloudFront requests an object from the origin server, which is S3 in our case. This helps us to only intercept once, when CloudFront needs to cache, so we do not put any overhead to our real user requests (viewer requests). Since we only invalidate cache if we have an update to the website, this will only happen per version per page.

Lambda@Edge function we use to redirect routes to specific index.html.

The logic here is simple. We use path library to check if the request uri has an extension or not. All the requests with specific extensions will be static assets, so we do not modify the request and let CloudFront do its job. For all the other requests, we generate a new uri by adding index.html to the end of uri. CloudFront then knows it needs to fetch this specific file for the request and cache it for all of the following requests until it gets invalidated.

It is as simple as this to intercept and alter CloudFront requests. You can check Lambda@Edge samples to see many other use cases you may find useful from A/B testing to website localizations. We also have another example where we needed to inject metadata to a Single Page Application with dynamic content. We managed to implement a Lambda function to generate dynamic HTML pages for our SPA without using any server-side rendering. It is a bit more complicated than this, but still good to see posibilities of Lambda@Edge.

If you would like to work on important, hard, fun, boring, and challenging projects with using AWS, React, Clojure and many other cutting edge technologies, feel free to get in touch with us!

--

--

Furkan Bayraktar
Rn Engineering

Co-founder & CTO @Scrintal | Clojure Advocate | Software Engineer