I'm trying to get batch redirection working in cloudflare workers. Here's an array of objects with to
and from
urls, some will be cross domain.
const redirects = [
{
"from": "https://some.domain.tld/product/*",
"to": "https://another.domain.tld/product/*"
},
]
I'd like to respect the wildcards and try to redirect based on the pathname of the url.
here's my attempt, but this is just for fixed pathnames and not cross-domain. It's kind of hard to test for cross-domain in the workers playground editor.
async function handleRequest(request) {
const url = new URL(request.url)
const host = url.hostname;
const path = url.pathname;
const queryStrings = url.search;
const location = redirects.find(r => {
return r.from.includes(path);
});
if (location) {
return Response.redirect('https://' + host + location.to + queryStrings, 301)
}
return fetch(request)
}
addEventListener("fetch", async event => {
event.respondWith(handleRequest(event.request))
})
How can I change this code so it respects redirects with wildcards? Wildcards will most likely always be at the end, some pathnames will not have wildcards, and it will not always be /product
but any pathname that's in the redirect object.
Updated after answer:
const redirects = [
{
"from": "https://red.domain.com/product-1/*",
"to": "https://blue.domain.com/product-1/*"
},
]
async function handleRequest(request) {
const url = 'https://red.domain.com/product-1/fees';
const location = redirects.reduce((loc, r) => {
let match = url.split(r.from.replace("*", "")[1]);
if (match) return r.to.replace("*", "") + match;
}, "");
if (location) {
return Response.redirect(location, 301)
}
return fetch(request)
}
addEventListener("fetch", async event => {
event.respondWith(handleRequest(event.request))
})
result:
https://blue.domain.com/product-1/h,,ps://red.domain.com/produc,-1/fees
You can match the whole URL to your redirects using Array#split()
, while getting the part "after" the wildcard back:
console.log(
"https://some.domain.tld/product/foo/bar/baz?test=baf".split("https://some.domain.tld/product/")[1]
)
For URLs that don't match this redirect, the result will be undefined
, so:
const redirects = [
{
"from": "https://some.domain.tld/product/*",
"to": "https://another.domain.tld/product/*"
},
]
async function handleRequest(request) {
const {url} = request;
const location = redirects.reduce((loc, r) => {
let match = url.split(r.from.replace("*","")[1]; // remove wildcard * for matching
if(match) return r.to.replace("*","") + match;
},"")
if (location) {
return Response.redirect(location, 301)
}
return fetch(request)
}
addEventListener("fetch", async event => {
event.respondWith(handleRequest(event.request))
})