LozanoMatheus
LozanoMatheus

Reputation: 407

Lambda@Edge URL redirect / path rewrite with NodeJS

I started learning NodeJS + Lambda@Edge a few days ago and one of the things that I was trying to do is the HTTP redirect/rewrite.

My current problem is when I try to use regex on the destination. For example, I want to redirect https://example.com/pt-BR/blog-posts/.... to https://example.com/pt/blog/...., just rewriting the beginning of the pathname.

Is it possible to do this redirection? I know that I could do it via NGINX, but I was wondering if I could do the same via Lambda@Edge and more "dynamic", like getting these URLs via DynamoDB.

const redirects = require('./redirects.json').map(
  ({ source, destination }) => ({
    source: new RegExp(source),
    destination
  })
);

exports.handler = async event => {
  const request = event.Records[0].cf.request;

  for (const { source, destination } of redirects) {
    if (source.test(request.uri)) {
      return {
        status: '301',
        statusDescription: 'Moved Permanently',
        headers: {
          location: [{ value: destination }]
        }
      };
    }
  }

  return request;
};

This is the redirects.json. The first two examples work perfectly, just the last one that is redirection to https://example.com/pt/blog/$1 instead of https://example.com/pt/blog/my-post-test001.

[
  {
    "source": "^/pt/pt",
    "destination": "/pt/"
  },
  {
    "source": "^/en/en",
    "destination": "/en/"
  },
  {
    "source": "^/pt-BR/blog-posts/(.*)",
    "destination": "/pt/blog/$1"
  }
]

These are the examples/docs that I checked: https://nodejs.org/docs/latest/api/url.html#url_url https://aws.amazon.com/blogs/networking-and-content-delivery/leveraging-external-data-in-lambdaedge/ https://www.npmjs.com/package/express-urlrewrite

Upvotes: 0

Views: 6507

Answers (2)

webjay
webjay

Reputation: 5508

Here's one for Node 12 that I use on Svedig to route /session/My-Workout to /session/index.html.

async function handler({ Records: [{ cf: { request } }] }) {
  const { uri } = request;
  if (uri.startsWith('/session/')) {
    return {
      ...request,
      uri: '/session/index.html',
    };
  }
  return request;
}

exports.handler = handler;

I would also recommend a Path Pattern of session/*.

Upvotes: 2

starpebble
starpebble

Reputation: 544

Yes, it's possible to rewrite a Cloudfront view request uri. The right approach depends on whether the target of the rewrite is also a Cloudfront object in the distribution origin. If it is, simply change the uri to the intended target.

  1. Don't return a 301.
  2. Alter request.uri with the rewrite uri path.
  3. Add the context and callback parameters to the function (event, context, callback)
  4. return the request object with callback(null,request);

Here is an example function that alters the uri of the cfrequest. The callback returns the same cfrequest to a different uri.

Example with NodeJS: rewrite the uri '/posts/' to '/posts/index.html'

const DEFAULT_OBJECT = 'index.html';
exports.handler = (event, context, callback) => {
  const cfrequest = event.Records[0].cf.request;
  if (cfrequest.uri.length > 0 && cfrequest.uri.charAt(cfrequest.uri.length - 1) === '/') {
    // e.g. /posts/ to /posts/index.html
    cfrequest.uri += DEFAULT_OBJECT;
  }
  callback(null, cfrequest);
  return true;
};     

Make sure to configure the Cloudfront behavior's viewer request with the rewrite Lambda@Edge function. That's different than an origin request lambda function.

Link: Hugo Quick Start, hosted on Cloudfront with lambda@edge

That'll be one happy lambda function!

Upvotes: 3

Related Questions