Skip to content

Instantly share code, notes, and snippets.

@bcnzer
Last active September 28, 2022 22:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bcnzer/c1f2008099ff9599d12a915ddec712ed to your computer and use it in GitHub Desktop.
Save bcnzer/c1f2008099ff9599d12a915ddec712ed to your computer and use it in GitHub Desktop.
Example of a Cloudflare Worker and Worker KV storage used to transfer/migrate traffic to alternatively infrastructure
addEventListener('fetch', event => {
event.passThroughOnException()
event.respondWith(handleRequest(event.request))
})
async function handleRequest(request) {
const maxBizId = await MIGRATION_SETTINGS.get('maxbizid')
const currentBusinessId = getBusinessIdFromCookie(request)
if (!maxBizId || maxBizId == 0 || !currentBusinessId) {
return await fetch(request)
}
const isTestBiz = await businessInKey(currentBusinessId, 'testbizids')
if (isTestBiz) {
// They're whitelisted as a test business so redirect them
return await redirect(request)
}
const isException = await businessInKey(currentBusinessId, 'bizidexceptions')
if (!isException && Number(currentBusinessId) <= Number(maxBizId)) {
// This biz is under the current max and is not an exception (i.e. VIPs) so redirect it
return await redirect(request)
}
return await fetch(request)
}
function getBusinessIdFromCookie(request) {
if (!request.headers) return null
let bizId = null
const cookies = request.headers.get('Cookie') || ""
if (cookies.includes(';')) {
// There's multiple cookies
const splitCookies = cookies.split(';')
splitCookies.forEach(cookie => {
if (cookie.includes('t-business')) {
bizId = cookie.split('=')[1]
}
})
} else {
if (cookies.includes('t-business')) {
bizId = cookie.split('=')[1]
}
}
return bizId
}
async function businessInKey(bizId, keyName) {
if (!bizId || bizId == 0) {
return false
}
const ids = await MIGRATION_SETTINGS.get(keyName)
return ids.split(',').indexOf(bizId.toString()) > -1
}
function requiresRewritingLinks(request, response){
// Change the string below to match whatever you need
return request.url.includes('[entermypartialurlstringhere]') &&
response.headers.get("Content-Type").includes("application/json")
}
async function rewriteResponseBody(response, target, replacement){
let bodyText = await response.text()
bodyText = bodyText.replace(new RegExp(target, 'g'), replacement)
return new Response(bodyText, {
headers: response.headers
})
}
async function redirect(request){
try {
const originalHost = 'app.myurl.com' // enter original URL here
const redirectHost = 'myapp.azurewebsites.net' // enter URL of what you're redirecting to
const redirectUrl = request.url.replace(originalHost, redirectHost)
let init = {
method: request.method,
headers: request.headers,
body: request.body,
redirect : "manual" // The stupidly important redirect parameter
}
let response = await fetch(new Request(redirectUrl, init))
if(requiresRewritingLinks(request, response)){
response = await rewriteResponseBody(response, redirectHost, originalHost)
}
let finalResponse = new Response(response.body, response)
finalResponse.headers.set('t-redirected', 'true') // Flag we added so it was clear your response was redirected
return finalResponse
} catch (e) {
return new Response(e)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment