URL短縮サービスをWorkers+KVで作った
なが~~いURL、どうやって渡す?
世の中には超ながいURLが転がっている時があります。基本、どんなに長くてもクリックさせれば開けますが…長すぎるせいで見た目が悪い!なんてこともありますし、相手に見せながら入力させるときに困ってしまいます。
そんなときに役立つのがURL短縮サービスですが、どうせなら自作してみたいものです。 Cloudflare Workers+KVを使えばあっという間に作れます。やってみましょう!
完成したもの
これです。URLを入力して短縮!ボタンを押すだけで生成されます。
中身(仕組み)
フレームワークにはHonoを使用しています。
まずは最初の部分から:
import { Hono } from 'hono'
import { customAlphabet } from 'nanoid'
const rooturl = 'https://r.a1z.uk' //jsで取得すればいいなんて言わないで
const nanoid = customAlphabet(
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
7,
)
type Env = {
SHORT_URLS: KVNamespace
}
const app = new Hono<{ Bindings: Env }>()
短縮URLのランダムな文字列にはnanoidのcustomAlphabetを使用しています。
HonoはKVの名前空間をバインドできるので、それも使っています。Honoさいこー!
/はこんな感じ。
app.get('/', (c) => {
return c.html(`
<html>
<head>
<meta charset="UTF-8" />
<meta name="description" content="ながーーーいURLを短縮っ!" />
<meta property="og:site_name" content="r.a1z.uk">
<meta name="theme-color" content="#FACEFA">
<title>Simple URL Shortener</title>
</head>
<h1>Simple URL Shortener</h1>
<div>
<span>ながーーーいURLを短縮できます</span>
</div>
<form action='/shorten' method='post'>
<div>
<label>URL</label>
<input type='url' name='url' required />
<button>短縮!</button>
</div>
</form>
</html>
<style>
html {
display: flex;
justify-content: center;
text-align: center;
}
</style>
`)
})
htmlのコードを返しています。シンプルですね✨
ここでボタンを押すと/shortenにPOSTされます。
async function shorten(kv: KVNamespace, url: string) {
const key = nanoid()
const createdAt = Date.now()
await kv.put(key, JSON.stringify({ url, createdAt }))
return { key }
}
app.post('/shorten', async (c) => {
const body = await c.req.parseBody<{url: string}>()
console.log(body)
const { url } = body
if (!url || typeof url !="string") {
return c.html('<p>無効なURLが入力されました。</p>', 400)
}
const { key } = await shorten(c.env.SHORT_URLS, url)
return c.html(`
<h1>生成しました!</h1>
<p id="url">${rooturl}/${key}</p>
<p>リダイレクト先: ${url}</p>
<style>
html {
display: flex;
justify-content: center;
text-align: center;
}
</style>
`)
})
こちらも短縮URLを生成するfunctionを実行させた後、htmlを返すシンプルな仕組みです。
そして、生成したkeyに対してアクセスすると
interface URL {
url: string
createdAt: number
}
async function getUrl(kv: KVNamespace, key: string) {
return kv.get<URL>(key, 'json')
}
app.get('/:key', async (c) => {
const key = c.req.param('key')
const res = await getUrl(c.env.SHORT_URLS, key)
if (!res) {
return c.text('存在しない短縮リンクです。', 404)
}
const url = res.url
return c.redirect(url, 301)
})
このように、kvからkeyを探して、resが空っぽの場合は404、そうでなければリダイレクト先を結果から抽出して301を返すようにしています。
Workers/Pagesが本当に素晴らしい
さて、今回のURL短縮サービスにはCloudflare Workersを使っています。せっかくなのでWorkers/Pagesの魅力を語ろうと思います。
今の時代では、簡単なサービスを、自分でサーバーを用意せずに(しかも無料で)作ることができるようになりました。 私はまだそこら辺の高校生(2024年時点)ですが、すごい時代だと思います。
Workers/PagesはサーバーレスでコードやWebページを動かせるサービスの一つで、とにかく簡単で速いのが魅力です。 似たようなサービスはたくさんありますが、とにかく制約が少ないです。使わないわけにはいきません。
実は私がWorkersを本格的に触り始めたのは二ヶ月前ぐらいで、まだまだ知らない事も多いのですが、毎日Workersの凄さを感じています。本当にいい所だらけ… だからこそ、簡単なWebページやサービスを作ろうとしている人には
「Cloudflare Workers/Pagesを使わないかい?」
と勧めています。怪しい人にしか見えないと思いますが、Cloudflare大好き人間としてはみんなに推したいのです。
もちろん、大規模なプロジェクトだったり、複雑な構造になってくると自分でサーバーを用意する方が圧倒的に幸せですが…
そうでなければWorkersなんかで十分です。私のプロジェクトは単純な物が多いので、徐々にWorkers/Pagesに移行しつつあります。
その方が管理だったりいろんな面で楽になります。電気代も減りますし…
というわけで、Cloudflare万歳な記事になっちゃいました。おわり!