Redirects using KV to store redirect map

Hi,

Second attempt at this script. Only one key and one value added to namespace for testing.

Key: /testredirect1/
Value: https://test.com/test/

KV Namespace: KV_REDIRECT_MATRIX

Test worker domain: my-worker.redirecttest.workers.dev

Worker script is supposed to get the pathname of the request URL. Check the Namespace for the existence of the pathname in the keys. If found then respond with 301 response code to the client with the redirected URL in the ‘value’.

This was tested on a worker.dev domain with the URL “https://my-worker.redirecttest.workers.dev/testredirect1/” but the returned was 500 internal server error.

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {

const requestURL = new URL(request.url)
const keySource = requestURL.pathname
  const value = await KV_REDIRECT_MATRIX.get(keySource)
  if (value !== null) {
    return Response.redirect(value, 301)
}
}

Any help appreciated

It worked for me when fixing the missing condition. KV is fine, I think is the missing return after the if

const handleRequest = async (request) => {
const requestURL = new URL(request.url);
const keySource = requestURL.pathname;
const value = await KV_REDIRECT_MATRIX.get(keySource);
if (value !== null) {
  return Response.redirect(value, 301);
}
return new Response("ok");
};

addEventListener("fetch", (event) => event.respondWith(handleRequest(event.request)));

1 Like

Do you have the KV bound? I would look at getting wrangler tail working for you so you can see what exception it’s throwing.

This approach is better instead of:

return await fetch(request);

1 Like

Binding. I was missing a binding env variable. And the code suggestions from everyone else.

Appreciate it guys! Bloody legends

1 Like

Just to plug :wink:

I made this - I don’t think it’s ready for everyone (I need to move it to Wrangler) but I’m hoping to fix that soon.

1 Like

Hello again… so another challenge… I’m trying to expand the script to you two Namspaces.

One contains the original Key: pathname and Value: Redirected_Destination. The second Namespace contains Key: pathname and the Value: 410. The 410 will be used as the response code.

Essentially I have two sets of inbound URLs that need 301 or 410.

Here is my code. The 301’s as per previous script (thank you @adaptive) still work as expected. But the pathname stored as a key in the new namespace returns a 200 and not a 410.

How have I scr3wed this up?

const handleRequest = async (request) => {

const requestURL = new URL(request.url);

const keySource = requestURL.pathname;

const redirectvalue = await KV_REDIRECT_MATRIX_BIND.get(keySource);

const fourTenvalue = await KV_FOURTEN_MATRIX_BIND.get(keySource);

if (fourTenvalue !== null) {

return response.status(fourTenvalue);

}

else (redirectvalue !== null) {

return Response.redirect(redirectvalue, 301);

}

//return new Response("ok");

// If request not in map, return the original request

return fetch(request);

};

addEventListener("fetch", (event) => event.respondWith(handleRequest(event.request)));

Use just one namespace, saves you :moneybag:
Store the data in JSON

{ "dest": "https://test.com/test/", "code": 410 }

then destruct into an object.

const handleRequest = async (request) => {
  const requestURL = new URL(request.url);
  const keySource = requestURL.pathname;
  const { dest, code } = await KV_REDIRECT_MATRIX_BIND.get(keySource, "json");
  if (dest !== null && code !== null) {
    return Response.redirect(dest, code);
  }
  return fetch(request);
};

addEventListener("fetch", (event) => event.respondWith(handleRequest(event.request)));

@adaptive Damn you’re good. But I can I redirect with a 410? I need one list of URLs to have response gone with no redirect and the other with 301 and redirect URL? No URL needed for 410

Then store like:

key1

{ "code": 410 }

key2

{ "dest": "https://test.com/test/", "code": 301 }

code:

const handleRequest = async (request) => {
  const requestURL = new URL(request.url);
  const keySource = requestURL.pathname;
  const { dest, code } = await KV_REDIRECT_MATRIX_BIND.get(keySource, "json");
  if (code === 301) {
    return Response.redirect(dest, code);
  } else if (code === 410) {
    return new Response("Gone", { status: 410, statusText: "Gone" });
  }
  return fetch(request);
};

addEventListener("fetch", (event) =>
  event.respondWith(handleRequest(event.request))
);
2 Likes

Elegant. And works perfectly in the test workers.dev. Unfortunately when routing through the custom domain, the proxied domain is returning 500 with Worker throwing 1101, js exception. I have logged a support ticket. Thanks @adaptive for all your help. I really appreciate it.

1 Like

The plot thickens.

It seems that when I add event.passThroughOnException() the script works as expected. I am not sure what the issue is but there you have it. An exception is thrown but the script works as expected with exceptions are ignored

New code:

const handleRequest = async (request) => {
  const requestURL = new URL(request.url);
  const keySource = requestURL.pathname;
  const { dest, code } = await KV_REDIRECT_MATRIX_BIND.get(keySource, "json");
  if (code === 301) {
    return Response.redirect(dest, code);
  } else if (code === 410) {
    return new Response("Gone", { status: 410, statusText: "Gone" });
  }
 return fetch(request);
  
  
};

addEventListener("fetch", (event) => {
  event.passThroughOnException()
  event.respondWith(handleRequest(event.request))
});

I highly recommend using wrangler tail to debug your exceptions.

Totally agree… learning how to do it today. Baby steps. Not easy to find freelancers who has good experience with Workers / KV. Anyone interested?

Just to update the community. The following now works. This was solved with help from another developer. (Thank you Luca)

const handleRequest = async (request) => {
  const requestURL = new URL(request.url);
  const keySource = requestURL.pathname;
  const res = await KV_REDIRECT_MATRIX_BIND.get(keySource, "json");
  const code = res?.code;
  const dest = res?.dest;
  if (code === 301) {
    return Response.redirect(dest, code);
  } else if (code === 410) {
    return new Response("Gone", { status: 410, statusText: "Gone" });
  }
  console.log("proxing to " + request.url);
  return fetch(request);
};

addEventListener("fetch", (event) => {

  event.respondWith(handleRequest(event.request));
});