Lambda@Edge function for handling redirects and rewrites
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
2
down vote
favorite
We're converting the City of Philadelphia's website to be served as static files. In order to support redirects and rewrites (URL masking), we decided to use a Lambda@edge function, which modifies (or responds to) the inbound request. I expect this will be maintained by other people so readability is very important. I would love your feedback on how this could be easier to understand and maintain.
const URL = require('url')
const inspect = require('util')
const TRAILING_SLASH = //$/
let compiledRegexes =
exports.handler = createHandler(require('../rules.json')) // expose to lambda
exports.createHandler = createHandler // expose for testing
function createHandler (rules)
return async function (event)
const request = event.Records[0].cf.request
const cleanPath = request.uri.toLowerCase().replace(TRAILING_SLASH, '')
log(event)
for (const rule of rules)
let newPath = null
if (rule.regex)
if (!compiledRegexes.hasOwnProperty(rule.pattern))
compiledRegexes[rule.pattern] = new RegExp(rule.pattern)
const regex = compiledRegexes[rule.pattern]
if (regex.test(cleanPath))
newPath = cleanPath.replace(regex, rule.replacement)
else if (cleanPath === rule.pattern)
newPath = rule.replacement
if (newPath !== null)
if (rule.type === 'rewrite') else
const response = createRedirect(newPath)
log(response)
return response
// If no matches, return unmodified request
log('no match')
return request
// Mutates request object
function setOrigin (request, origin)
const url = new URL(origin)
const protocol = url.protocol.slice(0, -1) // remove trailing colon
const path = url.pathname.replace(TRAILING_SLASH, '')
request.origin =
custom:
domainName: url.hostname,
protocol,
port: (protocol === 'https') ? 443 : 80,
path,
sslProtocols: ['TLSv1.2', 'TLSv1.1'],
readTimeout: 5,
keepaliveTimeout: 5,
customHeaders:
request.headers.host = [
key: 'host', value: url.hostname
]
function createRedirect (newUri)
return
status: '301',
statusDescription: 'Moved Permanently',
headers:
location: [
key: 'Location', value: newUri
]
function log (data)
if (process.env.NODE_ENV === 'test') return
// use util.inspect so objects aren't collapsed
console.log(inspect(data, false, 10))
A few example rules from rules.json
:
redirects
"pattern": "/old",
"replacement": "https://example.com/new",
"type": "redirect"
rewrites
"pattern": "/old(/.+)?",
"regex": true,
"replacement": "$1",
"origin": "https://example.com/new",
"type": "rewrite"
(I definitely don't love the "API" of how these rules are configured, and I think they could be simplified or merged. Would love any ideas here too!)
Thanks so much for your time.
javascript node.js lambda
add a comment |Â
up vote
2
down vote
favorite
We're converting the City of Philadelphia's website to be served as static files. In order to support redirects and rewrites (URL masking), we decided to use a Lambda@edge function, which modifies (or responds to) the inbound request. I expect this will be maintained by other people so readability is very important. I would love your feedback on how this could be easier to understand and maintain.
const URL = require('url')
const inspect = require('util')
const TRAILING_SLASH = //$/
let compiledRegexes =
exports.handler = createHandler(require('../rules.json')) // expose to lambda
exports.createHandler = createHandler // expose for testing
function createHandler (rules)
return async function (event)
const request = event.Records[0].cf.request
const cleanPath = request.uri.toLowerCase().replace(TRAILING_SLASH, '')
log(event)
for (const rule of rules)
let newPath = null
if (rule.regex)
if (!compiledRegexes.hasOwnProperty(rule.pattern))
compiledRegexes[rule.pattern] = new RegExp(rule.pattern)
const regex = compiledRegexes[rule.pattern]
if (regex.test(cleanPath))
newPath = cleanPath.replace(regex, rule.replacement)
else if (cleanPath === rule.pattern)
newPath = rule.replacement
if (newPath !== null)
if (rule.type === 'rewrite') else
const response = createRedirect(newPath)
log(response)
return response
// If no matches, return unmodified request
log('no match')
return request
// Mutates request object
function setOrigin (request, origin)
const url = new URL(origin)
const protocol = url.protocol.slice(0, -1) // remove trailing colon
const path = url.pathname.replace(TRAILING_SLASH, '')
request.origin =
custom:
domainName: url.hostname,
protocol,
port: (protocol === 'https') ? 443 : 80,
path,
sslProtocols: ['TLSv1.2', 'TLSv1.1'],
readTimeout: 5,
keepaliveTimeout: 5,
customHeaders:
request.headers.host = [
key: 'host', value: url.hostname
]
function createRedirect (newUri)
return
status: '301',
statusDescription: 'Moved Permanently',
headers:
location: [
key: 'Location', value: newUri
]
function log (data)
if (process.env.NODE_ENV === 'test') return
// use util.inspect so objects aren't collapsed
console.log(inspect(data, false, 10))
A few example rules from rules.json
:
redirects
"pattern": "/old",
"replacement": "https://example.com/new",
"type": "redirect"
rewrites
"pattern": "/old(/.+)?",
"regex": true,
"replacement": "$1",
"origin": "https://example.com/new",
"type": "rewrite"
(I definitely don't love the "API" of how these rules are configured, and I think they could be simplified or merged. Would love any ideas here too!)
Thanks so much for your time.
javascript node.js lambda
add a comment |Â
up vote
2
down vote
favorite
up vote
2
down vote
favorite
We're converting the City of Philadelphia's website to be served as static files. In order to support redirects and rewrites (URL masking), we decided to use a Lambda@edge function, which modifies (or responds to) the inbound request. I expect this will be maintained by other people so readability is very important. I would love your feedback on how this could be easier to understand and maintain.
const URL = require('url')
const inspect = require('util')
const TRAILING_SLASH = //$/
let compiledRegexes =
exports.handler = createHandler(require('../rules.json')) // expose to lambda
exports.createHandler = createHandler // expose for testing
function createHandler (rules)
return async function (event)
const request = event.Records[0].cf.request
const cleanPath = request.uri.toLowerCase().replace(TRAILING_SLASH, '')
log(event)
for (const rule of rules)
let newPath = null
if (rule.regex)
if (!compiledRegexes.hasOwnProperty(rule.pattern))
compiledRegexes[rule.pattern] = new RegExp(rule.pattern)
const regex = compiledRegexes[rule.pattern]
if (regex.test(cleanPath))
newPath = cleanPath.replace(regex, rule.replacement)
else if (cleanPath === rule.pattern)
newPath = rule.replacement
if (newPath !== null)
if (rule.type === 'rewrite') else
const response = createRedirect(newPath)
log(response)
return response
// If no matches, return unmodified request
log('no match')
return request
// Mutates request object
function setOrigin (request, origin)
const url = new URL(origin)
const protocol = url.protocol.slice(0, -1) // remove trailing colon
const path = url.pathname.replace(TRAILING_SLASH, '')
request.origin =
custom:
domainName: url.hostname,
protocol,
port: (protocol === 'https') ? 443 : 80,
path,
sslProtocols: ['TLSv1.2', 'TLSv1.1'],
readTimeout: 5,
keepaliveTimeout: 5,
customHeaders:
request.headers.host = [
key: 'host', value: url.hostname
]
function createRedirect (newUri)
return
status: '301',
statusDescription: 'Moved Permanently',
headers:
location: [
key: 'Location', value: newUri
]
function log (data)
if (process.env.NODE_ENV === 'test') return
// use util.inspect so objects aren't collapsed
console.log(inspect(data, false, 10))
A few example rules from rules.json
:
redirects
"pattern": "/old",
"replacement": "https://example.com/new",
"type": "redirect"
rewrites
"pattern": "/old(/.+)?",
"regex": true,
"replacement": "$1",
"origin": "https://example.com/new",
"type": "rewrite"
(I definitely don't love the "API" of how these rules are configured, and I think they could be simplified or merged. Would love any ideas here too!)
Thanks so much for your time.
javascript node.js lambda
We're converting the City of Philadelphia's website to be served as static files. In order to support redirects and rewrites (URL masking), we decided to use a Lambda@edge function, which modifies (or responds to) the inbound request. I expect this will be maintained by other people so readability is very important. I would love your feedback on how this could be easier to understand and maintain.
const URL = require('url')
const inspect = require('util')
const TRAILING_SLASH = //$/
let compiledRegexes =
exports.handler = createHandler(require('../rules.json')) // expose to lambda
exports.createHandler = createHandler // expose for testing
function createHandler (rules)
return async function (event)
const request = event.Records[0].cf.request
const cleanPath = request.uri.toLowerCase().replace(TRAILING_SLASH, '')
log(event)
for (const rule of rules)
let newPath = null
if (rule.regex)
if (!compiledRegexes.hasOwnProperty(rule.pattern))
compiledRegexes[rule.pattern] = new RegExp(rule.pattern)
const regex = compiledRegexes[rule.pattern]
if (regex.test(cleanPath))
newPath = cleanPath.replace(regex, rule.replacement)
else if (cleanPath === rule.pattern)
newPath = rule.replacement
if (newPath !== null)
if (rule.type === 'rewrite') else
const response = createRedirect(newPath)
log(response)
return response
// If no matches, return unmodified request
log('no match')
return request
// Mutates request object
function setOrigin (request, origin)
const url = new URL(origin)
const protocol = url.protocol.slice(0, -1) // remove trailing colon
const path = url.pathname.replace(TRAILING_SLASH, '')
request.origin =
custom:
domainName: url.hostname,
protocol,
port: (protocol === 'https') ? 443 : 80,
path,
sslProtocols: ['TLSv1.2', 'TLSv1.1'],
readTimeout: 5,
keepaliveTimeout: 5,
customHeaders:
request.headers.host = [
key: 'host', value: url.hostname
]
function createRedirect (newUri)
return
status: '301',
statusDescription: 'Moved Permanently',
headers:
location: [
key: 'Location', value: newUri
]
function log (data)
if (process.env.NODE_ENV === 'test') return
// use util.inspect so objects aren't collapsed
console.log(inspect(data, false, 10))
A few example rules from rules.json
:
redirects
"pattern": "/old",
"replacement": "https://example.com/new",
"type": "redirect"
rewrites
"pattern": "/old(/.+)?",
"regex": true,
"replacement": "$1",
"origin": "https://example.com/new",
"type": "rewrite"
(I definitely don't love the "API" of how these rules are configured, and I think they could be simplified or merged. Would love any ideas here too!)
Thanks so much for your time.
javascript node.js lambda
asked Jun 8 at 21:51
Tobias Fünke
1485
1485
add a comment |Â
add a comment |Â
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f196141%2flambdaedge-function-for-handling-redirects-and-rewrites%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password