Skip to content

Instantly share code, notes, and snippets.

@firxworx
Created June 9, 2022 02:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save firxworx/423f536f5487486a894f3fa0ccb21748 to your computer and use it in GitHub Desktop.
Save firxworx/423f536f5487486a894f3fa0ccb21748 to your computer and use it in GitHub Desktop.
AWS Lambda@Edge for rewriting request URI - reverse proxy for static sites and apps hosted with S3 + CloudFront CDN
'use strict'
/**
* Minimal implementation of an AWS 'Lambda@Edge' solution for rewriting a request URI.
*
* This Edge Lambda can support static sites + front-end apps hosted on AWS via S3 + CloudFront CDN,
* including those built by popular frameworks such as NextJS (e.g. via NextJS' `next export` static HTML export feature).
*
* An Edge Lambda provides control and can help meet real-world requirements that arise in the development of non-trivial
* front-end web applications, e.g. involving headers, with query strings, etc. that may not be supported (or at least
* elegantly supported) by "shortcut" AWS services such as AWS Amplify or app hosting services such as Netlify.
*
* Edge Lambdas like this example improve the behaviour of S3's static website hosting feature, which has potentially
* undesirable behaviours by design, e.g. issuing an HTTP 302 response to requests that omit a trailing slash.
*
* @see {@link https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/}
* @see {@link https://github.com/aws-samples/aws-lambda-edge-workshops/blob/master/Workshop1/Lab4_PrettyUrls/README.md}
* @see {@link https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html#lambda-event-structure-request}
*/
exports.handler = (event, _context, callback) => {
const hasEndingSlashRegex = /\/$/
const hasFileExtensionRegex = /(.+)\.[a-zA-Z0-9]{2,5}$/
// extract request from the CloudFront event
const request = event.Records[0].cf.request
const requestUri = request.uri || ''
// if logic involving http headers is required...
// const headers = request.headers // array of request headers
// if logic involving the query string is required...
// const params = querystring.parse(request.querystring) // requires import `const querystring = require('querystring')`
// if the request uri ends in '/' then replace the trailing slash with /index.html
if (requestUri.match(hasEndingSlashRegex)) {
request.uri = requestUri.replace(/\/$/, '/index.html')
}
// if the request uri is not for a file (i.e. no file extension) then append /index.html
if (!requestUri.match(hasFileExtensionRegex)) {
request.uri = requestUri + '/index.html'
}
if (requestUri !== request.uri) {
console.log(`Rewrite request uri '${requestUri}' to '${request.uri}'`)
}
return callback(null, request)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment