Published on

URI Redirects with CloudFront Functions

Part 6 of "Deploy Static Website To AWS"

Table of Contents

Overview

The Problem

Although navigation works well within the next.js application, refreshing the webpage or navigating directly to a path (e.g example.com/path/to/page) results in a 404 Not Found error. Alternatively, it may redirect to based on the error codes as defined in the distribution config.

CloudFormation Error Configuration

When adding .html to the end of the path (e.g example.com/path/to/page.html), the navigation works as expected.

The Goal

One solution to rectify this is to simply modify the request object adding .html at the end of every page. CloudFront Functions is used to receive incoming request and decide whether .html needs to be added to the path before passing the request on. Lambda@Edge functions could also be used, however is slower and more expensive. Here is a good article comparing CloudFront functions and Lambda@Edge.

CloudFormation Functions

Implementation

AWS Console

Create the Function

Create the function in CloudFront > Functions.

Specify the name and description and define the request transformation behavior. In this instance, .html (if not already present) is appended to any page. We also need to ensure that requests for other content are not altered. In the below example, the path of these request start with /static and /_next, and should not be altered.

function handler(event) {
    var request = event.request;
    var uri = request.uri;
    
    if (uri.startsWith("/static") || uri.startsWith('/_next') || uri.endsWith('.html')) {
        return request;
    }
    
    request.uri += '.html';
    return request;
}

Ensure that any changes are saved

Test

Once the function code is saved, test the function by trying different paths to ensure all requests are handled.

CloudFront Functions Test

Publish

Once tested, publish the function

Link the distribution behavior to the new function by editing the behavior in CloudFront > Distributions > Distribution > Behaviors

CloudFront Distribution Behavior

Associate the function. Ensure that the function is added to the viewer request

CloudFront Function Association

Once added, visit the webpage in different browsers and devices to ensure that cached copies are not being returned. The function code may need to be updated based on the specific path requirements.

Infrastructure as Code

The following will be added to the existing infrastructure pipeline see Part 3B.

Define CloudFront Function

See the CloudFormation config for more information.

# serverless.yml
resources:
  Resources:
    # ...
    RedirectFunction:
      Type: AWS::CloudFront::Function
      Properties:
        AutoPublish: true
        FunctionCode: >
          function handler(event) {
            var request = event.request;
            var uri = request.uri;
            
            if (uri.startsWith("/static") || uri.startsWith('/_next') || uri.endsWith('.html')) {
                return request;
            }
            
            request.uri += '.html';
            return request;
          }
        FunctionConfig:
          Comment: 'Ensure .html is appended to page paths'
          Runtime: cloudfront-js-1.0
        Name: "redirectFunction"
# serverless.yml

resources:
  Resources:
    # ...
    WebAppCloudFrontDistribution:
      # ...
      Type: AWS::CloudFront::Distribution
      Properties:
        DistributionConfig:
          DefaultCacheBehavior:
            FunctionAssociations:
              - EventType: viewer-request
                FunctionARN: !GetAtt RedirectFunction.FunctionMetadata.FunctionARN