Cloudflare PagesとAstroでURL短縮サービスを構築する
AI生成の要約
この記事では、Cloudflare PagesとAstroを使用してURL短縮サービスを構築する方法を紹介します。この記事では、環境設定、AstroとCloudflareの統合、Cloudflare KVの設定、ページの実装とデプロイについて説明します。これらの手順に従うことで、完全に機能するURL短縮サービスを構築することができます。
Prerequisite
- Docker
- VSCode
- Cloudflareアカウント
環境設定
VSCodeの開発コンテナを使用します
VSCodeでF1を押します
Dev Containers: Add Dev Container Configuration Files...
を選択します
node.js
環境を選択します:
以下は私が使用したdevcontainer.json
とDockerfile
です
{
"name": "Untitled Node.js project",
"build": {
"dockerfile": "Dockerfile"
},
"remoteUser": "node",
"features": {
"ghcr.io/devcontainers/features/common-utils:2": {}
},
"forwardPorts": [
4321, // for astro dev server
8976 // for wrangler login
],
"customizations": {
"vscode": {
"extensions": [
"astro-build.astro-vscode",
"svelte.svelte-vscode",
"dbaeumer.vscode-eslint",
"GitHub.copilot",
"GitHub.copilot-chat"
]
}
}
}
forwardPorts
は後で開発のために必要です
FROM node:22
# Install basic development tools
RUN apt update && apt install -y less man-db sudo
# Ensure default `node` user has access to `sudo`
ARG USERNAME=node
RUN echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
# Set `DEVCONTAINER` environment variable to help with orientation
ENV DEVCONTAINER=true
他のVSCode開発コンテナについては、別の記事を参照してください
Astroの設定
コンテナに入った後、公式ツールを使用してAstroファイルを生成します
npm create astro@latest
# dir Where should we create your new project?
# ./astro
# tmpl How would you like to start your new project?
# A basic, minimal starter
# deps Install dependencies?
# Yes
# git Initialize a new git repository?
# Yes
生成されたファイルは/astro
フォルダにあります。すべての内容を移動しました
mv astro/* .
rm -rf astro
開発サーバーを起動してみて、初期画面が表示されるはずです
npm run dev
Cloudflare Integration
Cloudflare Integrationを追加します
npx astro add cloudflare
自動的にファイルを設定してくれるはずですが、いくつかの設定を追加する必要があります:
export default defineConfig({
output: "server",
adapter: cloudflare({
platformProxy: {
enabled: true,
},
}),
})
このURL短縮サービスは純粋な静的ウェブサイトではないので、AstroがデフォルトでSSRを使用するようにoutput: 'server'
を設定します
platformProxy.enabled
は、ローカルでCloudflareの機能を使用できるようにするためのものです
詳細については、公式ドキュメントを参照してください
Cloudflare KVの設定
こののURL短縮サービスは、短縮URLとキー値ペアを保存する必要があります。ここではCloudflare KV
を使用します
wranglerにログイン
wrangler
はCloudflareの公式ツールです。まずログインしましょう
npx wrangler login
ブラウザがポップアップするはずですが、開発コンテナでは自動的にポップアップしないため、手動でURLをコピーしてブラウザに貼り付ける必要があります
同意すると、ページはポート8976にリダイレクトしようとしますが、失敗するかもしれません
しかし、devcontainer.json
でこのポートを開いているので、正常にログインできるはずです
KV Namespaceの作成
データを保存するための名前空間を作成し、SHORT_TO_URL
と名付けます
npx wrangler@latest kv:namespace create SHORT_TO_URL
ターミナルからIDを取得し、wrangler.toml
に追加します
[[kv_namespaces]]
binding = "SHORT_TO_URL"
id = "[YOUR ID HERE]"
開発環境がSHORT_TO_URL
を認識するようにするために、env.d.ts
を追加します
/// <reference types="astro/client" />
type KVNamespace = import("@cloudflare/workers-types").KVNamespace;
type ENV = {
SHORT_TO_URL: KVNamespace;
};
// use a default runtime configuration (advanced mode).
type Runtime = import("@astrojs/cloudflare").Runtime<ENV>;
declare namespace App {
interface Locals extends Runtime {}
}
詳細については、公式ドキュメントを参照してください
.wrangler
フォルダが表示されましたが、バージョン管理に追加する必要はないようですので、.gitignore
に追加します:
.wrangler/
ページの実装
3つのエンドポイントを用意します:
src/pages/index.astro
- ホームページ。静的で、ユーザーがURLを入力して送信するためのフォームを準備します
src/pages/shorten.ts
- URLを受け取り、短縮されたslugを返します
src/pages/[slug].ts
- slugを受け取り、保存されたURLにリダイレクトします
src/pages/index.astro
このページは基本的にインタラクティブなフォームが必要で、SSRは必要ありません。prerender = true
を追加して指定します
こちらを参照してください
---
export const prerender = true;
---
フォームの実装にはSvelteを使用します
npx astro add svelte
CSS部分は省略しますが、index.astro
では、コンポーネントをインタラクティブにするためにclient:load
として指定する必要があります
<Form client:load />
フォームの内容は通常のフロントエンド実装と同じです。GitHubを参照してください
src/pages/shorten.ts
このエンドポイントはURLを受け取り、短縮されたslugを返すために使用されます
md5暗号化を使用するので、まずパッケージをインストールします:
npm i -S js-md5
slugを計算した後、locals
から以前に設定したSHORT_TO_URL
を取得できます
import type { APIRoute } from "astro"
import { md5 } from "js-md5"
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
export const POST: APIRoute = async ({ request, locals }) => {
try {
const body = await request.json()
const url = new URL(body.url)
let hashed = Number.parseInt(md5.hex(url.href), 16)
let slug = ""
for (let i = 0; i < 6; i++) {
slug += charset[hashed % charset.length]
hashed = Math.floor(hashed / charset.length)
}
const { SHORT_TO_URL } = locals.runtime.env
await SHORT_TO_URL.put(slug, url.href)
return new Response(JSON.stringify({ slug }))
}
catch (e) {
return new Response(JSON.stringify({ error: "Invalid URL" }), { status: 400 })
}
}
src/pages/[slug].ts
このエンドポイントは受け取ったslugを処理し、以前に保存されたURLをクエリしてリダイレクトを提供する必要があります
import type { APIRoute } from "astro"
export const GET: APIRoute = async ({ params, locals, redirect }) => {
const slug: string = params.slug ?? ""
const { SHORT_TO_URL } = locals.runtime.env
const url = await SHORT_TO_URL.get(slug)
if (!url) {
return new Response(JSON.stringify({ error: "Not found" }), { status: 404 })
}
return redirect(url, 301)
}
デプロイ
package.json
にビルドとデプロイコマンドを設定できます
{
"scripts": {
// ...
"deploy": "astro build && wrangler pages deploy",
}
}
npm run deploy
成功!しかし、私のドメイン名は長すぎて、全く短縮されませんでした 🙃
疑問
最初はCloudflare Pagesに含まれるデプロイ機能を使用するように設定しましたが、この機能だけを使用するとワーカーが自動的に生成されません。 つまり、静的ページのみが正常にデプロイされ(他のページは404が表示されます)
ローカルからwrangler pages deploy
を使用するだけでうまくいくようです