Last active
June 12, 2025 10:05
-
-
Save maple3142/54c387768493db16cf755c41157f2b8b to your computer and use it in GitHub Desktop.
url shortener for cf workers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
addEventListener('fetch', (event) => { | |
event.respondWith( | |
handleRequest(event.request).catch( | |
(err) => new Response(err.stack, { status: 500 }) | |
) | |
); | |
}); | |
const ID_LEN = 6 | |
const SEC_PER_DAY = 60 * 60 * 24 | |
const MIN_DAYS = 1 | |
const MAX_DAYS = 7 | |
const DEFAULT_DAYS = 1 | |
const HOME = ` | |
<!DOCTYPE html> | |
<title>Url Shortener</title> | |
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.css"> | |
<form method="POST" action="/new"> | |
<div> | |
<label for="url">Url:</label> | |
<input id="url" name="url"> | |
</div> | |
<div> | |
<label for="days">Days:</label> | |
<input id="days" name="days" type="number" value="${DEFAULT_DAYS}" min="${MIN_DAYS}" max="${MAX_DAYS}"> | |
</div> | |
<button type="submit">Create</button> | |
</form> | |
` | |
const CREATED = url => ` | |
<!DOCTYPE html> | |
<title>Url Shortener - Success</title> | |
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.css"> | |
<div> | |
<input value="${url}" onclick="this.select();document.execCommand('copy')" style="width: 100vh;"> | |
</div> | |
` | |
async function handleRequest(request) { | |
const { pathname } = new URL(request.url) | |
if (pathname === '/') { | |
return new Response(HOME, { | |
headers: { 'Content-Type': 'text/html' }, | |
}) | |
} | |
if (pathname === '/new' && request.method === 'POST') { | |
const fd = await request.formData() | |
const url = fd.get('url') | |
const days = parseInt(fd.get('days')) | |
if (MIN_DAYS <= days && days <= MAX_DAYS) { | |
const id = await (async () => { | |
while(true) { | |
const id = Math.random().toString(36).slice(2, 2 + ID_LEN) | |
if (await LINKS.get(id) === null) { | |
return id | |
} | |
} | |
})() | |
await LINKS.put(id, url, { | |
expirationTtl: days * SEC_PER_DAY | |
}) | |
const newUrl = new URL(`/${id}`, request.url).toString() | |
return new Response(CREATED(newUrl), { | |
headers: { 'Content-Type': 'text/html' }, | |
}) | |
} | |
else { | |
return new Response('Invalid days') | |
} | |
} | |
const url = await LINKS.get(pathname.slice(1)) | |
if (url !== null) { | |
return new Response('Redirecting...', { | |
status: 302, | |
headers: { | |
'Location': url | |
} | |
}) | |
} | |
return new Response('Not found', { | |
status: 404 | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment