Cloudflare Workers入門!無料で始めるサーバーレス開発の第一歩
はじめに:サーバーレス開発の夜明けとCloudflare Workers
今日のWeb開発において、サービスを迅速に立ち上げ、高いスケーラビリティとコスト効率を両立させることは、全ての開発者の願いです。このニーズに応える技術の一つが「サーバーレス」であり、その中でも特に注目を集めているのが「Cloudflare Workers」です。
「サーバーレス」と聞くと、「サーバーがない」という誤解を招きがちですが、実際には「開発者がサーバーの管理を意識しなくて済む」という意味合いが強いです。サーバーのプロビジョニング、パッチ適用、スケーリングといった煩雑な作業はクラウドプロバイダーに任せ、開発者はアプリケーションのコードロジックに集中できるのがサーバーレスの最大の魅力です。
Cloudflare Workersは、このサーバーレスコンピューティングを「エッジ」で実現するという、ユニークかつ強力なアプローチを提供します。エッジとは、ユーザーに最も近いネットワークの末端を指し、そこでコードが実行されることで、超低レイテンシと優れたパフォーマンスを実現します。さらに、Cloudflareの広大なネットワークインフラストラクチャの上に構築されているため、強力なセキュリティと信頼性も兼ね備えています。
そして何よりも素晴らしいのは、Cloudflare Workersが提供する無料プランの存在です。個人プロジェクト、学習、プロトタイピング、あるいは小規模な本番環境であっても、無料で多くの機能を試すことができ、サーバーレス開発の第一歩を気軽に踏み出すことが可能です。
この記事では、Cloudflare Workersの基本的な概念から、開発環境のセットアップ、具体的なコードの書き方、そして無料プランで利用できる各種機能までを網羅的に解説します。約5000語という大ボリュームで、あなたのサーバーレス開発の旅を強力にサポートすることを目指します。さあ、Cloudflare Workersの世界へ飛び込みましょう!
1. サーバーレスとは?その利点と課題
Cloudflare Workersを理解する上で、まず「サーバーレス」という概念を深く掘り下げておく必要があります。
1.1. 従来のサーバーモデルとの比較
従来のWebアプリケーション開発では、開発者は通常、以下のいずれかの方法でサーバーを管理してきました。
- 物理サーバー/仮想マシン (VM): サーバーのOSからアプリケーションまで、全てを自分で管理します。高い自由度がありますが、運用負荷も非常に高いです。
- コンテナ (例: Docker): アプリケーションと依存関係をコンテナとしてパッケージ化し、コンテナオーケストレーションシステム (例: Kubernetes) で管理します。VMよりはポータビリティと管理性が向上しますが、やはり基盤となるサーバーの管理は必要です。
これに対し、サーバーレス (Serverless Computing) は、開発者がサーバーそのものを意識することなく、コードの実行環境を提供するモデルです。特に代表的なのが FaaS (Function as a Service) と呼ばれる形態で、イベント(HTTPリクエスト、データベースの変更、ファイルアップロードなど)をトリガーとして、あらかじめ定義された関数(コードスニペット)を実行します。
1.2. サーバーレスの主要な利点
サーバーレスがこれほどまでに普及しているのには、明確なメリットがあるからです。
-
究極のスケーラビリティ:
従来のサーバーでは、トラフィックの急増に対応するために、事前にサーバーの台数を増やしたり、オートスケーリングを設定したりする必要がありました。サーバーレスでは、プロバイダーが自動的に必要な数のインスタンスを立ち上げてくれます。これにより、トラフィックの変動に柔軟に対応し、大量のリクエストを捌くことが可能になります。極端な話、リクエストがゼロであればインスタンスもゼロになり、コストもゼロです。 -
圧倒的なコスト効率 (従量課金):
サーバーレスの課金モデルは「従量課金」が基本です。これは、コードが実行された時間(CPU時間)や、処理されたリクエスト数、データ転送量などに応じて費用が発生する仕組みです。アイドル状態のサーバーに課金されることがないため、リソースの無駄を最小限に抑え、特にアクセス頻度が低いサービスや、アクセスが予測不能なサービスにおいて高いコスト効率を発揮します。無料枠が充実しているプロバイダーも多く、個人開発者にとっては非常に魅力的な点です。 -
運用負荷の劇的な軽減:
サーバーのパッチ適用、OSのアップデート、セキュリティ設定、ネットワーク構成、ハードウェアの故障対応など、サーバー運用には多大な時間と専門知識が必要です。サーバーレスでは、これらのインフラストラクチャ管理は全てプロバイダーに任せることができます。開発者はコードの記述とデプロイに集中できるため、開発サイクルが短縮され、イノベーションを加速できます。 -
開発の迅速化とフォーカス:
インフラのセットアップや管理に時間を費やす必要がないため、開発者はビジネスロジックの実装に専念できます。これにより、アイデアからサービス公開までのリードタイムが大幅に短縮され、市場の変化に迅速に対応できるようになります。
1.3. サーバーレスの課題
もちろん、サーバーレスにも考慮すべき課題があります。
-
コールドスタート (Cold Start):
関数がしばらく実行されていない場合、プロバイダーはリソースを解放します。次にリクエストが来た際、再び関数を初期化(起動)する必要があり、この初期化に要する時間が「コールドスタート」です。この時間は数ミリ秒から数秒かかる場合があり、特にレイテンシに敏感なアプリケーションでは考慮が必要です。ただし、Cloudflare Workersは、V8 JavaScriptエンジンの特性とエッジコンピューティングのアーキテクチャにより、このコールドスタートが極めて短い(数ミリ秒以下)ことで知られています。 -
ベンダーロックイン (Vendor Lock-in):
特定のクラウドプロバイダーのサーバーレスサービスを利用すると、そのプロバイダー固有のAPIやサービスに強く依存することになります。これにより、将来的に別のプロバイダーへ移行する際に、コードの改修や再設計が必要になる可能性があります。 -
デバッグと監視の複雑さ:
サーバーレス環境は分散型であり、従来のモノリシックなアプリケーションとは異なるデバッグ・監視手法が求められます。ログの集約、分散トレーシング、メトリクスの収集など、専用のツールやサービスを活用する必要があります。 -
長期実行処理への不向き:
サーバーレス関数は、一般的に短時間で完結するタスクに適しています。多くのプロバイダーが関数の最大実行時間に制限を設けており(例: 数分〜15分)、長時間のバッチ処理やストリーミング処理などには不向きな場合があります。
これらの利点と課題を理解した上で、Cloudflare Workersがどのようにこれらの課題を克服し、独自の強みを発揮しているのかを見ていきましょう。
2. Cloudflare Workersの概要:エッジコンピューティングの力
Cloudflare Workersは、上記で解説したサーバーレスのメリットを享受しつつ、さらに「エッジ」という概念を加えることで、これまでのサーバーレスとは一線を画す体験を提供します。
2.1. エッジコンピューティングとは?
エッジコンピューティングとは、データが生成される場所や、ユーザーに最も近いネットワークの「エッジ」(末端)でコンピューティング処理を行う概念です。これに対し、従来のクラウドコンピューティングは、中央集権的なデータセンターで処理を行います。
Cloudflareは世界275以上の都市に広がる広大なネットワークを持っています。ユーザーがWebサイトにアクセスすると、Cloudflareのネットワークがそのリクエストを受け取ります。Workersは、このCloudflareのエッジロケーションで直接コードを実行します。
2.2. Workersがエッジで動くことの意味
Workersがエッジで実行されることには、以下のような計り知れないメリットがあります。
-
超低レイテンシ (Super Low Latency):
ユーザーの物理的な位置に最も近いデータセンターでコードが実行されるため、リクエストが遠く離れた中央データセンターまで往復する時間(ネットワーク遅延)を大幅に短縮できます。これにより、Webサイトの応答速度が向上し、ユーザー体験が劇的に改善されます。特に、グローバルに展開するサービスや、リアルタイム性が求められるアプリケーションで威力を発揮します。 -
優れた耐障害性:
Cloudflareのネットワークは非常に堅牢で、単一障害点(SPOF)を排除するように設計されています。Workersは複数のエッジロケーションに自動的にデプロイされ、ある場所で問題が発生しても、別の場所のインスタンスがすぐに処理を引き継ぐことができます。 -
Cloudflareインフラとの統合:
WorkersはCloudflareの既存の強力なサービス(DDoS保護、WAF、CDN、ロードバランシングなど)とシームレスに連携します。これにより、開発者はインフラのセキュリティやパフォーマンスに悩むことなく、アプリケーションロジックに集中できます。Webサイトの入口でリクエストを処理するため、悪意のあるトラフィックをブロックしたり、キャッシュを効率的に利用したりといったことが容易になります。 -
驚異的なコールドスタート性能:
Cloudflare Workersは、Google Chromeにも採用されている高性能なJavaScriptエンジン「V8」のIsolates(アイソレーツ)という軽量な実行環境を利用しています。これにより、新しいWorkersインスタンスの起動時間が極めて短く、数ミリ秒、あるいはそれ以下という驚異的なコールドスタート性能を実現しています。従来のサーバーレス関数で懸念されがちなコールドスタートの課題を、Workersはほぼ完全に克服しています。
2.3. V8 JavaScriptエンジンベース
WorkersはJavaScript (およびTypeScript) で記述され、V8エンジン上で動作します。これは、Web開発者が慣れ親しんだ言語と実行環境であり、学習コストが低いというメリットがあります。また、npmエコシステムから数多くのライブラリを利用できるため、開発効率も高いです。
2.4. 主要なユースケース
Cloudflare Workersはその特性上、非常に多岐にわたるユースケースに対応できます。
-
APIプロキシ・ルーティング:
incomingリクエストのURLやヘッダーに応じて、異なるバックエンドAPIへルーティングしたり、レスポンスを加工して返したりします。CORSヘッダーの付与や認証情報の付与なども可能です。 -
コンテンツ改変・最適化:
HTML、CSS、JavaScript、画像などのコンテンツを、リクエストに応じて動的に改変・最適化します。例えば、モバイルユーザー向けに画像を縮小したり、特定の国のユーザー向けに言語を切り替えたりできます。 -
ABテスト:
incomingリクエストの一部を異なるバージョンのWebサイトや機能に振り分け、ユーザー体験をテストします。 -
リダイレクト:
複雑な条件に基づいたURLのリダイレクトルールを設定し、SEOフレンドリーなサイト構造を維持します。 -
セキュリティ対策:
特定のIPアドレスからのアクセスをブロックしたり、カスタム認証ロジックを実装して不正アクセスを防いだりします。Rate Limitingの実装もWorkersで可能です。 -
認証・認可:
JWT (JSON Web Token) の検証、APIキーのチェックなど、認証・認可のゲートウェイとして機能します。 -
小規模APIバックエンド:
Workers KVやWorkers R2といったストレージサービスと連携し、軽量なデータストアとして、あるいは簡易的なCRUD (作成、読み取り、更新、削除) APIを提供します。
これらのユースケースはごく一部であり、Workersの柔軟性により、アイデア次第で無限の可能性を秘めています。
3. Cloudflare Workersの無料プランでできること
Cloudflare Workersの最大の魅力の一つは、その手厚い無料プランです。個人開発者、学生、あるいは気軽にサーバーレス開発を始めたい方にとって、これほど魅力的なスタート地点はありません。
3.1. 無料枠の詳細
Cloudflare Workersの無料プランは、以下の主要なリソースに対して十分な枠を提供しています。
-
リクエスト数: 1日あたり100,000リクエスト
これは非常に generous な数値です。1ヶ月に換算すると約300万リクエストにもなり、多くの小規模プロジェクトや個人ブログ、APIゲートウェイとしては十分すぎるほどの量です。もしこの上限を超えても、従量課金(100万リクエストあたり$0.15)で非常に低コストで利用を続けられます。 -
CPU時間: 1日あたり50ミリ秒
Workerが実際に処理に費やすCPU時間です。これはリクエスト数とは異なり、Workerのコードがどれだけ複雑で実行時間が長いかによって消費されます。多くのWebサイトのコンテンツ改変やシンプルなAPI処理では、数ミリ秒で完了するため、これも十分な量です。 -
スクリプト数: 最大100ワーカー (Workers Scripts)
異なるワーカーを最大100個デプロイできます。これにより、複数の異なるサービスや機能をWorkersとして分離して管理できます。 -
ストレージ (Workers KV / Workers R2):
後述しますが、Workersに付随するストレージサービスも無料枠が提供されます。
この無料枠は、学習目的はもちろん、個人ブログのカスタマイズ、Discordボットのバックエンド、軽量なAPI、短縮URLサービスなど、多岐にわたるプロジェクトで活用できます。無料で始められるため、気軽に試行錯誤できるのが大きな利点です。
3.2. Workers KV (Key-Value Store) の無料枠
Workers KVは、Workersから高速にアクセスできる分散型のKey-Valueストアです。シンプルながら非常に強力で、設定情報、キャッシュデータ、セッション情報、カウンタ、小規模なデータストレージなど、さまざまな用途に利用できます。
無料プランでは、以下の枠が提供されます。
- 読み取りリクエスト: 1日あたり100,000リクエスト
- 書き込み/削除リクエスト: 1日あたり1,000リクエスト
- ストレージ容量: 1GB
この無料枠も、一般的なユースケースでは十分な量です。KVは、エッジに近い場所で高速に読み書きできるため、レイテンシを重視するアプリケーションに最適です。
3.3. Workers R2 (S3互換オブジェクトストレージ) の無料枠
Workers R2は、Amazon S3と互換性のあるオブジェクトストレージサービスです。静的ファイル(画像、動画、PDF、JavaScriptファイルなど)の保存や配信に適しています。S3互換APIを提供するため、既存のS3ツールやライブラリをそのまま利用できる点も魅力です。そして最大の特長は、エグレス料金(データ転送費)がゼロであることです。これは、大量のファイルを配信する際にコストを劇的に削減できることを意味します。
無料プランでは、以下の枠が提供されます。
- ストレージ容量: 10GB
- 読み取りリクエスト: 1日あたり1,000,000リクエスト
- 書き込みリクエスト: 1日あたり100,000リクエスト
R2の無料枠も非常に手厚く、個人サイトの画像配信、Webアセットのホスティング、ユーザーアップロードファイルの保存など、多くの場面で活用できます。エグレス料金無料は、特にCDNと組み合わせる際に大きなアドバンテージとなります。
3.4. Durable Objectsの概要(無料枠の制限)
Durable Objectsは、Cloudflare Workersの中でも特に先進的な機能の一つで、ステートフルなサーバーレスアプリケーションを構築することを可能にします。従来のサーバーレス関数はステートレス(状態を持たない)であることが一般的でしたが、Durable Objectsは、特定のリクエストに対して「常に同じインスタンス」を起動し、そのインスタンスが状態を維持できるという保証を提供します。これにより、リアルタイムチャット、オンラインゲームのルーム管理、コラボレーションツールなど、ステートフルな処理が求められるアプリケーションの構築が可能になります。
無料プランではDurable Objectsも利用可能ですが、利用可能なリソース(読み取り/書き込み数、接続数など)に制限があります。ただし、小規模なプロトタイピングや学習には十分活用できます。
このように、Cloudflare Workersの無料プランは、単にコードを実行できるだけでなく、永続ストレージやオブジェクトストレージまで含めて提供されるため、本格的なアプリケーション開発の入り口として非常に優れています。
4. 開発環境の準備
Cloudflare Workersを始めるには、いくつかの準備が必要です。これらのステップは比較的簡単で、すぐに開発を始められます。
4.1. Cloudflareアカウントの作成
まずは、Cloudflareの公式サイトにアクセスし、無料アカウントを作成します。
https://www.cloudflare.com/ja-jp/
- Cloudflareのウェブサイトにアクセスし、「サインアップ」または「無料でサインアップ」をクリックします。
- メールアドレスとパスワードを入力し、アカウントを作成します。
- メールアドレスの認証を完了します。
Cloudflareアカウントが作成できたら、ダッシュボードにログインして、Workersの管理画面などを確認することができます。
4.2. Node.jsとnpmのインストール
Cloudflare Workersの開発には、Node.jsとそれに付属するパッケージマネージャーであるnpm(Node Package Manager)が必要です。これらはWorkersを管理するためのCLIツールであるwrangler
の実行に利用されます。
Node.jsの公式サイトから、ご自身のOSに合ったインストーラーをダウンロードしてインストールしてください。
https://nodejs.org/
インストールが完了したら、ターミナルまたはコマンドプロンプトを開き、以下のコマンドを実行して、正しくインストールされているか確認します。
bash
node -v
npm -v
それぞれバージョン番号が表示されれば、インストールは成功です。
4.3. wrangler
CLIツールのインストールとセットアップ
wrangler
は、Cloudflare Workersをローカルで開発し、デプロイするための公式CLI(コマンドラインインターフェース)ツールです。Node.jsとnpmがインストールされていれば、以下のコマンドで簡単にインストールできます。
bash
npm install -g wrangler
-g
オプションは、グローバルにインストールすることを意味し、どのディレクトリからでもwrangler
コマンドを使えるようになります。
インストールが完了したら、Cloudflareアカウントにwrangler
を認証する必要があります。
bash
wrangler login
このコマンドを実行すると、Webブラウザが開き、Cloudflareの認証ページが表示されます。指示に従ってCloudflareアカウントにログインし、「許可」をクリックしてください。
認証が成功すると、ターミナルに戻り「Successfully logged in.」のようなメッセージが表示されます。これでwrangler
があなたのCloudflareアカウントと連携できるようになりました。
これでCloudflare Workersを開発する準備が整いました!
5. 初めてのCloudflare Workersデプロイ
開発環境の準備ができたので、実際にCloudflare Workersをデプロイしてみましょう。ここでは「Hello World」を出力する簡単なWorkerを作成します。
5.1. プロジェクトの作成
まず、新しいWorkerプロジェクトを作成するためのディレクトリを作成し、そこに移動します。
bash
mkdir my-first-worker
cd my-first-worker
次に、wrangler generate
コマンドを使って、新しいWorkerプロジェクトのひな形を生成します。
bash
wrangler generate my-first-worker-project
my-first-worker-project
は、新しく生成されるプロジェクトのディレクトリ名です。このコマンドを実行すると、カレントディレクトリ内にmy-first-worker-project
という新しいディレクトリが作成され、その中にWorkerのひな形ファイルが自動的に生成されます。
もし、カレントディレクトリに直接プロジェクトを作成したい場合は、プロジェクト名を指定せず、wrangler generate --name my-first-worker-project .
のように現在のディレクトリを指定することも可能です。ただし、ここではmy-first-worker-project
という名前のサブディレクトリが作成されるものとして進めます。
プロジェクトが生成されたら、そのディレクトリに移動します。
bash
cd my-first-worker-project
5.2. プロジェクト構造の解説
生成されたプロジェクトの中身を見てみましょう。主要なファイルは以下の通りです。
my-first-worker-project/
├── wrangler.toml
└── src/
└── index.js
-
wrangler.toml
:
このファイルは、Workerの設定ファイルです。Workerの名前、デプロイ対象の環境(プロダクション、ステージングなど)、関連するリソース(KV Namespace、R2バケットなど)、環境変数などを定義します。wrangler generate
で生成された直後のwrangler.toml
は、以下のようになっているはずです。toml
name = "my-first-worker-project"
main = "src/index.js"
compatibility_date = "2023-12-08"
*name
: このWorkerの名前です。Cloudflareダッシュボード上でもこの名前で表示されます。これはユニークである必要があります。
*main
: Workerのコードが記述されているファイルのパスを指定します。デフォルトではsrc/index.js
です。
*compatibility_date
: Workerの実行環境の互換性日付を指定します。これは、Cloudflare Workersプラットフォームが進化しても、過去のコードが意図せず動作変更されないようにするためのものです。通常は、wrangler
が自動的に最新の日付を設定してくれます。 -
src/index.js
:
Workerのメインコードを記述するファイルです。HTTPリクエストを処理するためのJavaScriptコードが含まれます。
5.3. src/index.js
のコード解説(Hello World)
src/index.js
ファイルを開いてみましょう。初期状態では、以下のようなコードが記述されています。
``javascript
npm run dev
/**
* Welcome to Cloudflare Workers! This is your first worker.
*
* - Runin your terminal to start a development server
npm run deploy` to publish your worker
* - Open a browser tab at http://localhost:8787/ to see your worker in action
* - Run
*
* Learn more at https://developers.cloudflare.com/workers/
*/
export default {
async fetch(request, env, ctx) {
return new Response(‘Hello World!’);
},
};
“`
このコードについて詳しく見ていきましょう。
-
export default { ... };
:
Cloudflare Workersは、ES Modules形式をサポートしており、export default
でWorkerのエントリポイントを定義します。エントリポイントは、通常はHTTPリクエストを処理するfetch
メソッドを含むオブジェクトです。 -
async fetch(request, env, ctx) { ... }
:
これがWorkersの最も重要な部分です。fetch
メソッドは、WorkerにHTTPリクエストが送られてくるたびに呼び出されます。これは非同期関数であるため、async
キーワードがついています。request
:Request
オブジェクトです。受信したHTTPリクエストに関する全ての情報(URL、メソッド、ヘッダー、ボディなど)が含まれています。env
: 環境変数やバインディングされたリソース(KV Namespace、R2バケット、Durable Objectなど)にアクセスするためのオブジェクトです。後ほど詳しく解説します。ctx
: 実行コンテキストオブジェクトです。特定の実行中にのみ有効な情報や、Workerのライフサイクルを管理するためのメソッド(例:waitUntil
)が含まれます。
-
return new Response('Hello World!');
:
fetch
メソッドは、Response
オブジェクトを返す必要があります。この例では、ステータスコード200(OK)で、ボディが「Hello World!」というテキストのHTTPレスポンスを生成しています。
このシンプルなコードが、あなたの最初のWorkerとして動きます。
5.4. ローカルでの開発サーバー起動
デプロイする前に、ローカルでWorkerの動作を確認できます。これは開発サイクルを速める上で非常に便利です。
プロジェクトのルートディレクトリで、以下のコマンドを実行します。
bash
wrangler dev
このコマンドを実行すると、ローカルに開発サーバーが起動し、Workerが実行されます。ターミナルには以下のようなメッセージが表示されるはずです。
``
wrangler dev` is experimental and may change. [実験的機能であるため、変更される可能性があります]
❯ yarn wrangler dev
▲ [WARNING]
Running my-first-worker-project
on http://localhost:8787
GET /
“`
ブラウザでhttp://localhost:8787
にアクセスしてみてください。「Hello World!」というテキストが表示されれば成功です。
wrangler dev
は、コードの変更を検知すると自動的にリロードしてくれるホットリロード機能も備えています。src/index.js
を編集して保存し、ブラウザをリロードしてみると、変更が即座に反映されるのが確認できます。
開発サーバーを停止するには、ターミナルでCtrl + C
を押します。
5.5. Workersへのデプロイ
ローカルでの動作確認が済んだら、いよいよCloudflare Workersにデプロイします。
プロジェクトのルートディレクトリで、以下のコマンドを実行します。
bash
wrangler deploy
wrangler
は、wrangler.toml
の設定に基づき、あなたのWorkerコードをCloudflareのグローバルネットワークにアップロードし、デプロイします。
デプロイが完了すると、ターミナルに以下のようなメッセージが表示されます。
``
wrangler deploy` is experimental and may change. [実験的機能であるため、変更される可能性があります]
❯ yarn wrangler deploy
▲ [WARNING]
Successfully published your Worker to
https://my-first-worker-project.
Current deployment ID:
…
“`
<YOUR_SUBDOMAIN>
の部分は、あなたのCloudflareアカウントに紐付けられた固有のサブドメイン名に置き換わっています。このURLにブラウザでアクセスしてみてください。
「Hello World!」
が表示されれば、見事Cloudflare Workersへのデプロイ成功です!
これで、あなたのWorkerはCloudflareのグローバルネットワーク上で稼働し、世界中のユーザーからのリクエストを処理できるようになりました。
これで、Cloudflare Workers開発の最初のステップを完了しました。次に、Workersのより詳細な機能と使い方を見ていきましょう。
6. Cloudflare Workersの基本的な使い方と機能
「Hello World」のデプロイに成功したところで、Workersが提供する主要な機能や、HTTPリクエストの処理方法について詳しく見ていきましょう。
6.1. HTTPリクエストの処理
WorkersはHTTPリクエストを処理するために設計されています。fetch
ハンドラ内でRequest
オブジェクトを読み込み、Response
オブジェクトを生成して返します。
6.1.1. Request
オブジェクトの操作
request
オブジェクトには、クライアントから送信されたHTTPリクエストに関するあらゆる情報が含まれています。
“`javascript
export default {
async fetch(request) {
const url = new URL(request.url); // リクエストURLをパース
const method = request.method; // HTTPメソッド (GET, POSTなど)
const headers = request.headers; // リクエストヘッダー
const userAgent = headers.get(‘User-Agent’); // 特定のヘッダー値を取得
let body = null;
if (request.method === 'POST' || request.method === 'PUT') {
// リクエストボディをJSONとしてパース
try {
body = await request.json();
} catch (e) {
// JSON以外のボディ形式 (text(), arrayBuffer(), formData() なども利用可能)
body = await request.text();
}
}
// クエリパラメータの取得
const param1 = url.searchParams.get('param1');
return new Response(`
Method: ${method}
URL: ${url.toString()}
User-Agent: ${userAgent}
Query Param 'param1': ${param1 || 'N/A'}
Body: ${body ? JSON.stringify(body, null, 2) : 'N/A'}
`, { headers: { 'Content-Type': 'text/plain' }});
},
};
“`
この例では、URL、メソッド、ヘッダー、クエリパラメータ、そしてリクエストボディの取得方法を示しています。特にrequest.json()
, request.text()
といった非同期メソッドは、ボディの形式に応じて使い分けます。
6.1.2. Response
オブジェクトの生成
WorkerはResponse
オブジェクトを返します。これにより、クライアントに送信されるHTTPレスポンスの全ての要素(ステータスコード、ヘッダー、ボディなど)を制御できます。
“`javascript
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/json') {
const data = {
message: 'This is a JSON response!',
timestamp: new Date().toISOString()
};
return new Response(JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' },
status: 200,
});
} else if (url.pathname === '/redirect') {
return Response.redirect('https://example.com', 301); // 永続リダイレクト
} else if (url.pathname === '/404') {
return new Response('Page Not Found', { status: 404 });
} else if (url.pathname === '/image') {
// 画像などのバイナリデータを返す例 (実際には fetch() で取得することが多い)
const imageData = new Uint8Array([/* バイナリデータ */]); // 例
return new Response(imageData, {
headers: { 'Content-Type': 'image/png' },
});
}
return new Response('Hello from Cloudflare Workers!', {
headers: { 'Content-Type': 'text/plain', 'X-Worker-Powered-By': 'Cloudflare' },
status: 200,
});
},
};
“`
new Response(body, options)
:Response
オブジェクトの基本的なコンストラクタです。body
: レスポンスボディとして返すデータ。文字列、Blob
、ArrayBuffer
、FormData
などが指定できます。options
: レスポンスのステータスコード (status
) やヘッダー (headers
) を設定するオブジェクトです。
Response.redirect(url, status)
: 特定のURLへリダイレクトするためのヘルパーメソッドです。status
には301
(永続的)や302
(一時的)などを指定します。
6.2. ルーティング
Workersでは、fetch
ハンドラ内でrequest.url
やrequest.method
を使って、リクエストのパスやメソッドに応じた処理を行うのが一般的です。
6.2.1. 基本的なIf/Else分岐
シンプルなルーティングであれば、if/else if
文で十分です。
“`javascript
export default {
async fetch(request) {
const url = new URL(request.url);
if (url.pathname === '/api/hello') {
return new Response('Hello API!', { status: 200 });
} else if (url.pathname === '/api/user' && request.method === 'POST') {
const userData = await request.json();
return new Response(`User created: ${userData.name}`, { status: 201 });
} else {
return new Response('Welcome to the Worker!', { status: 200 });
}
},
};
“`
6.2.2. itty-router
などのライブラリの利用例
より複雑なルーティングや、Middlewareのような機能を実装したい場合は、itty-router
やCloudflare Worker Router
などの軽量なルーティングライブラリを利用すると便利です。
itty-router
を例に取ります。まず、プロジェクトにインストールします。
bash
npm install itty-router
次に、src/index.js
で利用します。
“`javascript
import { Router } from ‘itty-router’;
// 新しいルーターインスタンスを作成
const router = Router();
// GET /api/hello に対応するルート
router.get(‘/api/hello’, async ({ request }) => {
return new Response(‘Hello from the API router!’, { status: 200 });
});
// POST /api/data に対応するルート
router.post(‘/api/data’, async ({ request }) => {
try {
const data = await request.json();
return new Response(JSON.stringify({ received: data, status: ‘success’ }), {
headers: { ‘Content-Type’: ‘application/json’ },
status: 200,
});
} catch (e) {
return new Response(‘Invalid JSON’, { status: 400 });
}
});
// ワイルドカードを使ったルーティング (例: /api/items/123)
router.get(‘/api/items/:id’, async ({ params }) => {
return new Response(Fetching item with ID: ${params.id}
, { status: 200 });
});
// 定義されていないパスへのフォールバック
router.all(‘*’, () => new Response(‘Not Found.’, { status: 404 }));
export default {
async fetch(request, env, ctx) {
// リクエストをルーターに渡して処理させる
return router.handle(request, env, ctx);
},
};
“`
itty-router
を使うことで、可読性が高く、構造化されたルーティングを簡単に実装できます。
6.3. 環境変数 (Environment Variables)
APIキーやデータベースの接続情報など、デプロイ環境ごとに異なる設定値や機密情報を扱うには、環境変数が最適です。Cloudflare Workersでは、wrangler.toml
ファイルまたはwrangler secret
コマンドで環境変数を設定し、Workerコードからenv
オブジェクトを介してアクセスします。
6.3.1. wrangler.toml
での設定
wrangler.toml
に直接記述する方法は、機密性の低い公開可能な設定値に適しています。
“`toml
wrangler.toml
name = “my-worker”
main = “src/index.js”
compatibility_date = “2023-12-08”
環境変数を [vars] セクションで定義
[vars]
MY_PUBLIC_VAR = “This is a public variable”
API_ENDPOINT = “https://api.example.com”
または、[env.<環境名>.vars] で環境ごとに定義
[env.production]
vars = { ENV_NAME = “production” }
[env.development]
vars = { ENV_NAME = “development” }
“`
Workerコードからのアクセス:
“`javascript
export default {
async fetch(request, env) {
const publicVar = env.MY_PUBLIC_VAR;
const apiEndpoint = env.API_ENDPOINT;
const envName = env.ENV_NAME; // デプロイ環境に応じた値
return new Response(`
Public Var: ${publicVar}
API Endpoint: ${apiEndpoint}
Environment Name: ${envName}
`);
},
};
“`
6.3.2. wrangler secret
コマンドでの安全な管理
APIキーなどの機密情報は、wrangler.toml
に直接記述するのではなく、wrangler secret
コマンドを使って安全に管理します。これにより、シークレットがバージョン管理システム(Gitなど)に誤ってコミットされるのを防ぎます。
bash
wrangler secret put MY_SECRET_KEY
コマンドを実行すると、ターミナルで値の入力を求められます。入力された値はCloudflareのシステムにセキュアに保存され、Workerが実行される際にenv
オブジェクトを通じて提供されます。
“`javascript
export default {
async fetch(request, env) {
const secretKey = env.MY_SECRET_KEY; // wrangler secret で設定した値
if (request.headers.get('X-Api-Key') !== secretKey) {
return new Response('Unauthorized', { status: 401 });
}
return new Response('Access Granted!');
},
};
“`
6.4. Workers KV (Key-Value Store)
Workers KVは、Key-Value形式のデータをエッジで高速に読み書きできる分散型データストアです。
6.4.1. Namespaceの作成
KVを利用するには、まずNamespace
を作成します。これは、KVストアの論理的な区画のようなものです。
wrangler.toml
にKV Namespaceを定義します。
“`toml
wrangler.toml
name = “my-worker-with-kv”
main = “src/index.js”
compatibility_date = “2023-12-08”
KV Namespaceを定義 (bindingはコードからアクセスするための名前)
[[kv_namespaces]]
binding = “MY_KV_NAMESPACE” # コード内で env.MY_KV_NAMESPACE としてアクセス
id = “
“`
wrangler.toml
に上記を記述し、wrangler deploy
を実行すると、Cloudflareが自動的にKV Namespaceを作成し、id
をwrangler.toml
に追記してくれます。または、CloudflareダッシュボードのWorkers > KVメニューから手動でNamespaceを作成し、そのIDをwrangler.toml
にコピーすることもできます。
6.4.2. コードでの利用例 (KV.put()
, KV.get()
, KV.delete()
)
env
オブジェクトを介してKV Namespaceにアクセスできます。
“`javascript
export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.searchParams.get(‘key’);
if (!key) {
return new Response('Please provide a key parameter.', { status: 400 });
}
if (url.pathname === '/set') {
const value = url.searchParams.get('value') || 'default_value';
await env.MY_KV_NAMESPACE.put(key, value); // データを書き込み
return new Response(`Key "${key}" set to "${value}" in KV.`, { status: 200 });
} else if (url.pathname === '/get') {
const value = await env.MY_KV_NAMESPACE.get(key); // データを読み込み
if (value) {
return new Response(`Value for "${key}": ${value}`, { status: 200 });
} else {
return new Response(`Key "${key}" not found.`, { status: 404 });
}
} else if (url.pathname === '/delete') {
await env.MY_KV_NAMESPACE.delete(key); // データを削除
return new Response(`Key "${key}" deleted.`, { status: 200 });
}
return new Response('KV Operations: /set?key=X&value=Y, /get?key=X, /delete?key=X', { status: 200 });
},
};
“`
この例では、URLのパスとクエリパラメータを使って、KVへのデータの書き込み、読み込み、削除を行っています。
6.5. Workers R2 (Object Storage)
Workers R2は、S3互換のオブジェクトストレージで、Workersから直接ファイルを操作できます。
6.5.1. バケットの作成
R2バケットも、wrangler.toml
で定義します。
“`toml
wrangler.toml
name = “my-worker-with-r2”
main = “src/index.js”
compatibility_date = “2023-12-08”
R2バケットを定義 (bindingはコードからアクセスするための名前)
[[r2_buckets]]
binding = “MY_R2_BUCKET” # コード内で env.MY_R2_BUCKET としてアクセス
bucket_name = “my-app-files” # R2バケットの名前 (Cloudflare内でユニークである必要あり)
“`
wrangler deploy
を実行すると、指定したbucket_name
でR2バケットが作成されます。
6.5.2. コードでの利用例 (R2.put()
, R2.get()
, R2.delete()
)
R2バケットへのアクセスも、KVと同様にenv
オブジェクトを通じて行います。
“`javascript
export default {
async fetch(request, env) {
const url = new URL(request.url);
const filename = url.searchParams.get(‘file’);
if (!filename) {
return new Response('Please provide a file parameter.', { status: 400 });
}
if (url.pathname === '/upload') {
// ファイルのアップロード例 (POSTリクエストのボディを受け取る)
const uploadBody = await request.text(); // ここではテキストとして仮定
await env.MY_R2_BUCKET.put(filename, uploadBody, {
httpMetadata: { contentType: 'text/plain' }, // ファイルの種類を指定
});
return new Response(`File "${filename}" uploaded to R2.`, { status: 200 });
} else if (url.pathname === '/download') {
// ファイルのダウンロード例
const object = await env.MY_R2_BUCKET.get(filename);
if (object === null) {
return new Response('File not found', { status: 404 });
}
return new Response(object.body, {
headers: { 'Content-Type': object.httpMetadata.contentType },
});
} else if (url.pathname === '/delete-file') {
// ファイルの削除例
await env.MY_R2_BUCKET.delete(filename);
return new Response(`File "${filename}" deleted from R2.`, { status: 200 });
}
return new Response('R2 Operations: /upload?file=X, /download?file=X, /delete-file?file=X', { status: 200 });
},
};
“`
この例では、URLのパスとクエリパラメータを使って、R2バケットへのファイルのアップロード(ボディは仮にテキストとしています)、ダウンロード、削除を行っています。put
メソッドの第三引数でhttpMetadata
を設定すると、ファイルのContent-Type
などを指定でき、ダウンロード時のブラウザでの表示に役立ちます。
6.6. Durable Objects (Stateful Serverless)
Durable Objectsは、特定のエンティティ(ユーザー、チャットルーム、ゲームセッションなど)の状態を単一のWorkerインスタンスで永続的に管理できる、革新的な機能です。
6.6.1. 概要とユニークな特徴
- 単一インスタンス保証: 特定のDurable Object IDに対しては、常に単一のWorkerインスタンスが起動し、そのIDに対する全てのリクエストを処理します。これにより、競合状態を心配することなく、インメモリで状態を管理できます。
- 長期接続: WebSocketのような長期接続をDurable Objectに直接ルーティングし、その状態をオブジェクト内で管理できます。
- ストレージ: 各Durable Objectインスタンスは、独自の永続ストレージ(KVのようなもの)を持ち、状態を保持できます。
6.6.2. 簡単な例示(カウンタ)
Durable Objectsを定義するには、まずsrc/index.js
とは別のファイル(例: src/DurableCounter.js
)でクラスとして定義します。
src/DurableCounter.js
:
“`javascript
export class DurableCounter {
constructor(state, env) {
this.state = state;
this.env = env; // env オブジェクトも Durable Object に渡される
// この Durable Object の永続ストレージを初期化
this.state.blockConcurrencyWhile(async () => {
this.value = (await this.state.storage.get(‘value’)) || 0;
});
}
// HTTP リクエストを処理するメソッド
async fetch(request) {
const url = new URL(request.url);
switch (url.pathname) {
case ‘/increment’:
this.value++;
await this.state.storage.put(‘value’, this.value); // 永続ストレージに保存
return new Response(this.value.toString());
case ‘/decrement’:
this.value–;
await this.state.storage.put(‘value’, this.value);
return new Response(this.value.toString());
case ‘/get’:
return new Response(this.value.toString());
default:
return new Response(‘Not Found’, { status: 404 });
}
}
}
“`
次に、メインのWorker (src/index.js
) からこのDurable Objectを呼び出します。
src/index.js
:
“`javascript
export default {
async fetch(request, env) {
const url = new URL(request.url);
const name = url.searchParams.get(‘name’) || ‘default_counter’; // カウンタの名前
// Durable Object のインスタンスを取得
// env.COUNTER は wrangler.toml で設定する Durable Object binding
const id = env.COUNTER.idFromName(name); // 名前からIDを生成(常に同じ名前なら同じIDになる)
const obj = env.COUNTER.get(id); // IDから Durable Object インスタンスを取得
// Durable Object に HTTP リクエストを転送
return obj.fetch(request);
},
};
“`
最後に、wrangler.toml
でDurable Objectを定義し、バインディングします。
“`toml
wrangler.toml
name = “my-worker-with-do”
main = “src/index.js”
compatibility_date = “2023-12-08”
Durable Object を定義
[[durable_objects.bindings]]
name = “COUNTER” # コード内で env.COUNTER としてアクセス
class_name = “DurableCounter” # Durable Object のクラス名
script_name = “my-worker-with-do” # どの Worker スクリプトで定義されているか (通常は同じスクリプト名)
“`
この設定でデプロイし、/increment?name=my_counter
や/get?name=my_counter
にアクセスすると、my_counter
という名前のDurable Objectが生成され、そのカウンター値が永続的に保持されるようになります。
6.7. Cron Triggers (スケジュール実行)
WorkersはHTTPリクエストだけでなく、定期的に実行されるタスク(Cron Triggers)としても設定できます。これにより、バッチ処理や外部サービスの定期的なチェックなどをサーバーレスで行うことができます。
wrangler.toml
にCron Triggersを設定します。
“`toml
wrangler.toml
name = “my-cron-worker”
main = “src/index.js”
compatibility_date = “2023-12-08”
Cron Trigger を定義
[[triggers]]
crons = [“0 * * * *”] # 毎時0分に実行 (Cron式)
“`
Workerコードでは、scheduled
メソッドを実装します。
“`javascript
export default {
// HTTP リクエストを処理する fetch メソッド
async fetch(request, env, ctx) {
return new Response(‘This Worker also handles HTTP requests.’);
},
// Cron Trigger で呼び出される scheduled メソッド
async scheduled(event, env, ctx) {
// ログにタイムスタンプを出力
console.log(Cron job ran at ${new Date(event.scheduledTime)}
);
// 例: 外部APIを呼び出す
try {
const response = await fetch('https://api.example.com/daily-report');
const data = await response.json();
console.log('Daily report received:', data);
// KVにデータを保存するなどの処理
// await env.MY_KV_NAMESPACE.put('last_report', JSON.stringify(data));
} catch (e) {
console.error('Failed to fetch daily report:', e);
}
// ctx.waitUntil() を使うと、関数の実行が終了しても非同期タスクが完了するまで待機できる
ctx.waitUntil(new Promise(resolve => setTimeout(resolve, 1000))); // 例: 1秒待機する非同期タスク
},
};
“`
crons
配列には、Cron式を複数指定できます。scheduled
メソッドはevent
オブジェクトを受け取り、event.scheduledTime
で実行予定時刻を取得できます。ctx.waitUntil()
は、scheduled
メソッドがリターンした後も、Workerが指定された非同期タスクが完了するまで実行を続けるように指示するために使用します。これにより、バックグラウンドでの非同期処理を安全に実行できます。
6.8. Workers AI (AIモデルの活用)
Cloudflare Workersは、Workers AIという機能を通じて、エッジで直接AIモデルを実行・推論できる強力な機能を提供します。これにより、追加のサーバーや複雑なAI環境のセットアップなしに、画像生成、テキスト生成、翻訳、埋め込みベクトル生成などのAI機能をアプリケーションに組み込むことができます。
Workers AIは無料で利用できるモデルと、有償プランで利用できるモデルがあります。無料枠は非常に手厚く、気軽にAI機能を試すことができます。
まず、wrangler.toml
でWorkers AIのバインディングを設定します。
“`toml
wrangler.toml
name = “my-worker-with-ai”
main = “src/index.js”
compatibility_date = “2023-12-08”
AI をバインド
[[ai_bindings]]
name = “AI” # コード内で env.AI としてアクセス
“`
次に、WorkerコードからAIモデルを呼び出します。
“`javascript
export default {
async fetch(request, env, ctx) {
const url = new URL(request.url);
if (url.pathname === '/generate-text') {
const prompt = url.searchParams.get('prompt') || 'Hello World!';
try {
// テキスト生成モデルを呼び出し
const response = await env.AI.run(
"@cf/mistral/mistral-7b-instruct-v0.1", // 利用するモデルのID
{
prompt: prompt,
max_tokens: 50,
}
);
return new Response(JSON.stringify(response), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error("AI inference error:", error);
return new Response(`AI inference failed: ${error.message}`, { status: 500 });
}
} else if (url.pathname === '/translate') {
const textToTranslate = url.searchParams.get('text') || 'Hello World!';
try {
const translation = await env.AI.run(
"@cf/meta/m2m100-1.2b", // 翻訳モデル
{
text: textToTranslate,
target_lang: "ja", // 日本語に翻訳
source_lang: "en", // 英語から翻訳
}
);
return new Response(JSON.stringify(translation), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error("Translation error:", error);
return new Response(`Translation failed: ${error.message}`, { status: 500 });
}
}
return new Response('Access /generate-text?prompt=Your_Prompt or /translate?text=Your_Text');
},
};
“`
env.AI.run()
メソッドを使って、指定したモデルID (@cf/mistral/mistral-7b-instruct-v0.1
など) と入力データ(プロンプト、テキストなど)を渡すことで、AI推論を実行できます。利用可能なモデルはCloudflareのWorkers AIドキュメントで確認できます。
Workers AIは、アプリケーションにインテリジェンスを追加するための強力な手段であり、無料プランでも多くの実験が可能です。
7. 実践的なユースケースの例
これまでに学んだCloudflare Workersの機能を使って、より実践的なユースケースのコード例を見ていきましょう。
7.1. 簡易APIプロキシ:CORSヘッダーの付与、特定のパスへのルーティング
フロントエンドから外部APIに直接アクセスする際、CORSポリシーに阻まれることがあります。Workersは、このCORSの問題を解決するためのプロキシとして機能します。
“`javascript
// src/index.js
export default {
async fetch(request) {
const url = new URL(request.url);
// リクエストが /proxy/ プレフィックスを持つ場合のみ処理
if (url.pathname.startsWith('/proxy/')) {
// プロキシ先のURLを構築
const targetUrl = 'https://api.example.com' + url.pathname.replace('/proxy', '') + url.search;
// 元のリクエストからヘッダーとメソッドをコピー
const init = {
method: request.method,
headers: new Headers(request.headers),
body: request.body, // POST/PUTなどのボディを転送
};
// CORS関連のヘッダーはプロキシ先には送らない (Workersで追加するため)
init.headers.delete('Origin');
init.headers.delete('Referer');
// ターゲットAPIにリクエストを転送
const response = await fetch(targetUrl, init);
// レスポンスヘッダーをコピー
const newResponse = new Response(response.body, response);
// CORSヘッダーを追加
newResponse.headers.set('Access-Control-Allow-Origin', '*'); // 任意のオリジンからのアクセスを許可
newResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
newResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
// OPTIONSリクエスト(プリフライト)への対応
if (request.method === 'OPTIONS') {
return new Response(null, {
status: 204, // No Content
headers: newResponse.headers,
});
}
return newResponse;
}
// それ以外のパスはデフォルトのレスポンス
return new Response('Access /proxy/your-api-path to use the API proxy.', { status: 200 });
},
};
“`
このWorkerは、/proxy/
で始まるパスへのリクエストを受け取り、api.example.com
に転送します。元のリクエストヘッダーを転送しつつ、CORS関連のヘッダーを適切に追加することで、異なるオリジンからのAPIアクセスを可能にします。
7.2. リダイレクトサービス:短縮URL、SEOフレンドリーなリダイレクト
Workersを使って、カスタムの短縮URLサービスや、特定の条件に基づいたSEOフレンドリーなリダイレクトを実現できます。
“`javascript
// src/index.js (Workers KVと連携)
export default {
async fetch(request, env) {
const url = new URL(request.url);
const path = url.pathname.slice(1); // 先頭のスラッシュを除去
// 例: KVに保存された短縮URLのリダイレクト
if (path) {
const longUrl = await env.SHORT_URLS.get(path); // env.SHORT_URLS は KV Namespace
if (longUrl) {
return Response.redirect(longUrl, 301); // 永続的なリダイレクト
}
}
// 特定のパスを別のパスにリダイレクト
if (url.pathname === '/old-page') {
return Response.redirect('https://example.com/new-page', 301);
}
// ユーザーエージェントに基づくリダイレクト (例: モバイルユーザーを特定ページへ)
const userAgent = request.headers.get('User-Agent') || '';
if (userAgent.includes('Mobi') || userAgent.includes('Android') || userAgent.includes('iPhone')) {
// return Response.redirect('https://example.com/mobile-version', 302); // 一時的なリダイレクト
}
// リダイレクトルールが見つからない場合のデフォルト
return new Response('Welcome to the Redirect Service! Try /old-page or a /short-code from KV.', { status: 200 });
},
};
“`
wrangler.toml (KV Namespaceの設定)
“`toml
wrangler.toml
name = “my-redirect-worker”
main = “src/index.js”
compatibility_date = “2023-12-08”
[[kv_namespaces]]
binding = “SHORT_URLS”
id = “
“`
このWorkerでは、KVに保存された短縮URL(例: my-worker.workers.dev/abc
-> https://very-long-url.com/something-long
)を解決したり、特定の旧URLから新URLへのリダイレクトを設定したりできます。
7.3. 画像最適化プロキシ (Workers Image Resizingの紹介)
Workers自体で画像処理を行うことも可能ですが、CloudflareはWorkers Image Resizingという専用の機能を提供しており、Workersから簡単に利用できます。これにより、リクエストに応じて画像をリサイズ、フォーマット変換、品質調整などを行えます。
“`javascript
// src/index.js
export default {
async fetch(request) {
const url = new URL(request.url);
// /image/ プレフィックスで画像URLを指定
// 例: https://your-worker.workers.dev/image/https://example.com/original.jpg?w=300
if (url.pathname.startsWith('/image/')) {
const imageUrl = url.pathname.replace('/image/', 'https://') + url.search;
const parsedImageUrl = new URL(imageUrl);
// Cloudflare Image Resizing のための画像URLパラメータ
// ここでは query string をそのまま利用しています
const imageOptions = {
cf: {
image: imageUrl, // 元の画像URL
width: url.searchParams.get('w') ? parseInt(url.searchParams.get('w')) : undefined,
height: url.searchParams.get('h') ? parseInt(url.searchParams.get('h')) : undefined,
quality: url.searchParams.get('q') ? parseInt(url.searchParams.get('q')) : undefined,
format: 'auto', // ブラウザに応じてWebP/AVIFに自動変換
}
};
// fetch API に cf オプションを渡す
const imageResponse = await fetch(parsedImageUrl, imageOptions);
// レスポンスヘッダーにキャッシュ制御を追加
const headers = new Headers(imageResponse.headers);
headers.set('Cache-Control', 'public, max-age=31536000'); // 1年間キャッシュ
return new Response(imageResponse.body, {
status: imageResponse.status,
statusText: imageResponse.statusText,
headers: headers,
});
}
return new Response('Access /image/https://example.com/your-image.jpg?w=300 to optimize an image.', { status: 200 });
},
};
“`
このWorkerは、URLパスとして与えられた外部の画像URLを、クエリパラメータで指定された幅(w
)、高さ(h
)、品質(q
)に従って最適化して返します。cf
オプションをfetch
の第二引数に渡すだけで、Cloudflareの画像最適化機能が自動的に適用されます。format: 'auto'
は、クライアントのブラウザがサポートする最適な画像フォーマット(WebP、AVIFなど)に自動的に変換して配信してくれるため、パフォーマンス向上に大きく貢献します。
7.4. フォーム送信エンドポイント:HTMLフォームからデータを受け取り、KV/R2に保存
静的なWebサイトに問い合わせフォームなどを設置する際、バックエンドサーバーなしでフォームデータを受け取りたい場合があります。Workersは、このフォームのエンドポイントとして機能できます。
“`javascript
// src/index.js (Workers KVと連携)
export default {
async fetch(request, env) {
const url = new URL(request.url);
if (request.method === 'POST' && url.pathname === '/submit-form') {
try {
const formData = await request.formData(); // application/x-www-form-urlencoded または multipart/form-data をパース
const name = formData.get('name');
const email = formData.get('email');
const message = formData.get('message');
if (!name || !email || !message) {
return new Response('Missing form fields.', { status: 400 });
}
const submissionId = crypto.randomUUID(); // ユニークなIDを生成
const submissionData = {
name,
email,
message,
timestamp: new Date().toISOString(),
};
// KVにフォームデータを保存
await env.FORM_SUBMISSIONS.put(submissionId, JSON.stringify(submissionData));
// R2にファイルを保存する例 (もしフォームがファイルアップロードを含む場合)
// const file = formData.get('uploaded_file');
// if (file instanceof File) {
// await env.MY_R2_BUCKET.put(`uploads/${submissionId}/${file.name}`, file.stream());
// }
return new Response('Form submitted successfully!', { status: 200 });
} catch (e) {
console.error('Form submission error:', e);
return new Response('Failed to process form submission.', { status: 500 });
}
}
return new Response('Send a POST request to /submit-form with form data.', { status: 200 });
},
};
“`
wrangler.toml (KV Namespaceの設定)
“`toml
wrangler.toml
name = “my-form-worker”
main = “src/index.js”
compatibility_date = “2023-12-08”
[[kv_namespaces]]
binding = “FORM_SUBMISSIONS”
id = “
“`
このWorkerは、HTMLフォームからのPOST
リクエストを受け取り、request.formData()
メソッドでフォームデータをパースします。パースされたデータは、Workers KVに保存されます。これにより、サーバーを立てることなく、静的サイトで動的なフォームを実現できます。
7.5. 簡易認証ゲートウェイ:APIキーチェック、JWT検証
特定のAPIエンドポイントへのアクセスを制限するために、Workersを認証ゲートウェイとして利用できます。
“`javascript
// src/index.js (wrangler secret で MY_API_KEY を設定している前提)
export default {
async fetch(request, env) {
const url = new URL(request.url);
// /api/secure へのアクセスのみ認証をチェック
if (url.pathname.startsWith('/api/secure')) {
const apiKey = request.headers.get('X-API-Key');
// APIキーの検証 (wrangler secret で設定した env.MY_API_KEY と比較)
if (!apiKey || apiKey !== env.MY_API_KEY) {
return new Response('Unauthorized: Invalid or missing API Key', { status: 401 });
}
// 認証成功の場合、実際のバックエンドにリクエストを転送
// 例: Cloudflare Pages Functions との連携や、外部APIへの転送
const targetUrl = 'https://your-backend-api.example.com' + url.pathname.replace('/api/secure', '');
const response = await fetch(targetUrl, request); // request オブジェクトをそのまま転送
return response;
}
// JWT検証の例 (joseライブラリなどを利用)
// if (url.pathname.startsWith('/api/jwt-secure')) {
// const authHeader = request.headers.get('Authorization');
// if (!authHeader || !authHeader.startsWith('Bearer ')) {
// return new Response('Unauthorized: Bearer token required', { status: 401 });
// }
// const token = authHeader.slice(7); // 'Bearer ' の部分を除去
// try {
// // ここでJWTの検証ロジックを実装 (例: JOSEライブラリを使用)
// // const { payload } = await jwtVerify(token, SECRET_KEY, { ... });
// return new Response('JWT verified. Access granted.', { status: 200 });
// } catch (e) {
// return new Response('Unauthorized: Invalid JWT', { status: 401 });
// }
// }
return new Response('Welcome! Access /api/secure with a valid X-API-Key header.', { status: 200 });
},
};
“`
このWorkerは、特定のパス(例: /api/secure
)へのリクエストに対して、X-API-Key
ヘッダーをチェックし、wrangler secret
で設定したAPIキーと一致しなければアクセスを拒否します。JWT認証の場合は、jose
のようなライブラリをインストールして利用することができます。これにより、バックエンドサービスに認証ロジックを実装する手間を省き、Workersで一元的に認証を管理できます。
これらの例は、Cloudflare WorkersがWeb開発のさまざまな側面でいかに強力で柔軟であるかを示しています。無料で始められるため、ぜひこれらのアイデアを参考に、自分自身のプロジェクトでWorkersを試してみてください。
8. デバッグとトラブルシューティング
開発中に問題が発生した場合に備え、Cloudflare Workersのデバッグとトラブルシューティングの方法を知っておくことは重要です。
8.1. wrangler dev
の利用
前述の通り、wrangler dev
コマンドはローカルでの開発サーバーを起動し、Workerの動作をリアルタイムで確認できます。
- ホットリロード: コードを変更してファイルを保存すると、自動的にWorkerが再ロードされます。
- ログ出力:
console.log()
などで出力したメッセージは、wrangler dev
を実行しているターミナルに直接表示されます。 - エラーの捕捉: コードにエラーがある場合、ターミナルにスタックトレースが表示され、問題の特定に役立ちます。
- 環境変数のテスト:
wrangler dev --env development
のように、特定の環境のwrangler.toml
設定を適用してテストできます。
ローカル開発環境は、イテレーションを高速化し、多くの問題をデプロイ前に解決するために不可欠です。
8.2. Cloudflareダッシュボードでのログ確認
本番環境にデプロイしたWorkerで問題が発生した場合、Cloudflareダッシュボードからログを確認できます。
- Cloudflareダッシュボードにログインします。
- 左側のメニューから「Workers & Pages」を選択します。
- 問題が発生しているWorkerを選択します。
- 「ログ」タブをクリックします。
ここでは、Workerの実行ログ、エラーログ、そしてconsole.log()
で出力したカスタムログがリアルタイムで表示されます。エラーが発生した場合は、エラーメッセージとスタックトレースを確認し、原因を特定できます。
無料プランでは、ログの保存期間や検索機能に制限がある場合がありますが、リアルタイムでの監視には十分役立ちます。
8.3. console.log()
デバッグ
最も基本的なデバッグ手法ですが、非常に効果的です。Workerコードの実行経路や変数の値を確認するために、console.log()
を挿入します。
“`javascript
export default {
async fetch(request) {
console.log(‘Request received:’, request.url); // リクエストURLをログ出力
const headers = request.headers;
console.log(‘User-Agent header:’, headers.get(‘User-Agent’)); // 特定のヘッダーをログ出力
try {
const data = await request.json();
console.log('Request body (JSON):', data); // リクエストボディをログ出力
} catch (e) {
console.log('Request body is not JSON or empty.');
}
// 何らかの処理...
let result = 'Success';
if (Math.random() < 0.5) {
result = 'Failure';
console.error('An error condition occurred!'); // エラーログとして出力
}
console.log('Worker execution finished with result:', result);
return new Response(`Processed: ${result}`);
},
};
“`
wrangler dev
で実行中にターミナルで、またはデプロイ後にCloudflareダッシュボードのログで、これらのメッセージを確認できます。
8.4. エラーハンドリング
予期せぬエラーが発生した場合に、ユーザーに適切なメッセージを返すため、または内部でログを記録するために、適切なエラーハンドリングを実装することが重要です。
javascript
export default {
async fetch(request) {
try {
// 外部API呼び出しなど、エラーが発生しうる処理
const response = await fetch('https://non-existent-api.example.com');
if (!response.ok) {
throw new Error(`External API error: ${response.status}`);
}
const data = await response.json();
return new Response(JSON.stringify(data), {
headers: { 'Content-Type': 'application/json' },
});
} catch (error) {
console.error('Caught an error:', error.message); // エラーをログに出力
// ユーザーには一般的なエラーメッセージを返す
return new Response('An unexpected error occurred. Please try again later.', {
status: 500,
headers: { 'Content-Type': 'text/plain' },
});
}
},
};
try...catch
ブロックを使用することで、Workerコード内で発生した例外を捕捉し、適切に処理できます。これにより、Workerがクラッシュするのを防ぎ、よりユーザーフレンドリーなエラーメッセージを提供できます。
これらのデバッグとトラブルシューティングのテクニックをマスターすることで、Cloudflare Workersの開発体験が大幅に向上するでしょう。
9. セキュリティとベストプラクティス
Cloudflare Workersで堅牢で安全なアプリケーションを構築するために、いくつかのセキュリティとベストプラクティスを遵守することが重要です。
9.1. 秘密情報の管理(Secrets)
APIキー、データベース認証情報、プライベートトークンなどの機密情報は、絶対にコードにハードコードしたり、バージョン管理システムにコミットしたりしないでください。
wrangler secret
の利用:
最も推奨される方法です。wrangler secret put MY_API_KEY
コマンドを使ってシークレットをCloudflareのセキュアなストレージに保存し、Workerコードからはenv.MY_API_KEY
としてアクセスします。これにより、シークレットがソースコードに含まれることを防ぎます。
9.2. 入力検証 (Input Validation)
Workerが受け取るリクエストのデータ(URL、クエリパラメータ、ヘッダー、ボディなど)は、常に信頼できないものとして扱ってください。悪意のある入力によって、予期せぬ動作やセキュリティ脆弱性(例: インジェクション攻撃)が発生する可能性があります。
- 型チェック: 期待するデータ型(文字列、数値、真偽値など)であることを確認します。
- 範囲チェック: 数値であれば、期待する範囲内にあるか確認します。
- 文字列のサニタイズ: データベースに保存したり、HTMLとしてレンダリングしたりする前に、特殊文字をエスケープまたは削除します。
- 正規表現: 特定のパターンに合致するかどうかを検証します(例: メールアドレスの形式)。
9.3. CORSポリシーの適用
WorkerがAPIとして機能する場合、Access-Control-Allow-Origin
ヘッダーを適切に設定し、許可されたオリジンからのアクセスのみを許可するようにしてください。*
を使用すると全てのオリジンからのアクセスを許可しますが、セキュリティリスクが高まります。
“`javascript
// 特定のオリジンのみ許可する場合
const allowedOrigin = ‘https://my-frontend-app.com’;
const origin = request.headers.get(‘Origin’);
if (origin && origin === allowedOrigin) {
response.headers.set(‘Access-Control-Allow-Origin’, origin);
} else {
// 許可されないオリジンからのリクエストには CORS ヘッダーを付けないか、エラーを返す
}
// 複数のオリジンを許可する場合
const allowedOrigins = [‘https://app1.com’, ‘https://app2.com’];
const origin = request.headers.get(‘Origin’);
if (origin && allowedOrigins.includes(origin)) {
response.headers.set(‘Access-Control-Allow-Origin’, origin);
}
“`
9.4. レートリミット(Workers自体、またはCloudflareのWAF機能)
不正なアクセスやDDoS攻撃からWorkerを保護するために、リクエストのレートリミット(制限)をかけることを検討してください。
- Workers KVを使用した簡易レートリミット:
KVにIPアドレスごとのリクエスト数を保存し、一定時間内のリクエスト数が閾値を超えた場合にブロックするロジックをWorker自身で実装できます。 - CloudflareのRate Limiting機能:
Cloudflareの有料プランで提供されるWAF(Web Application Firewall)機能の一部として、より高度なレートリミットルールを設定できます。これはWorkersの実行前に適用されるため、Workerのリソース消費を抑えることができます。
9.5. コードのモジュール化と再利用
大規模なWorkerや複数のWorkerを開発する場合、コードをモジュール化することで、可読性、保守性、再利用性が向上します。
- ES Modules:
import
とexport
を使って、コードを複数のファイルに分割します。 - ヘルパー関数: 共通の処理(例: 日付フォーマット、エラーレスポンスの生成)は、ヘルパー関数として抽出し、再利用可能なモジュールにします。
“`javascript
// src/utils.js
export function createJsonResponse(data, status = 200) {
return new Response(JSON.stringify(data), {
headers: { ‘Content-Type’: ‘application/json’ },
status: status,
});
}
// src/index.js
import { createJsonResponse } from ‘./utils’;
export default {
async fetch(request) {
// …
return createJsonResponse({ message: ‘Hello from Worker!’ });
},
};
“`
9.6. バージョン管理とCI/CD
Gitなどのバージョン管理システムを利用し、コードの変更履歴を管理しましょう。また、CI/CD(継続的インテグレーション/継続的デリバリー)パイプラインを構築することで、コードのテスト、デプロイプロセスを自動化し、開発効率と信頼性を高めることができます。
- GitHub Actions / GitLab CI/CD:
wrangler
CLIはCI/CD環境での利用を想定して設計されており、簡単に自動デプロイを設定できます。
10. 次のステップと発展
Cloudflare Workersの基本的な使い方をマスターした今、さらにその可能性を広げるための次のステップを見ていきましょう。
10.1. Cloudflare Pagesとの連携(静的サイトホスティングとWorkersバックエンド)
Cloudflare Pagesは、静的サイトやシングルページアプリケーション(SPA)を高速にホスティングできるサービスです。Pagesは、Gitリポジトリと連携して自動デプロイされるため、非常に手軽にWebサイトを公開できます。
PagesとWorkersを組み合わせることで、静的なフロントエンドにWorkersをバックエンドAPIとして連携させることができ、フルスタックアプリケーションをサーバーレスで構築できます。
- Pages Functions: Pagesのプロジェクト内でWorkersの機能を利用できるPages Functionsも提供されており、Pagesと密接に連携するAPIを簡単に構築できます。
10.2. Hono, SvelteKitなどのフレームワークとの統合
Workersは非常に低レベルなAPIを提供しますが、開発体験を向上させるために、Workers向けのフレームワークやツールキットも登場しています。
-
Hono:
Workers向けに最適化された軽量で高速なWebフレームワークです。ルーティング、ミドルウェア、リクエスト・レスポンスの扱いなどをより簡単に記述できます。Express.jsのような感覚でWorker開発ができます。 -
SvelteKit / Astro など:
モダンなWebフレームワークの中には、ビルドターゲットとしてWorkersをサポートしているものもあります。これにより、SSR (Server-Side Rendering) やAPIルートをWorkers上で実行できるようになり、高いパフォーマンスと開発効率を両立できます。
10.3. より高度なWorkers機能
Cloudflare Workersには、この記事で紹介しきれなかったさらに高度な機能があります。
-
Service Bindings:
複数のWorker間で通信を行うための仕組みです。Worker AからWorker Bのfetch
ハンドラを直接呼び出すことができます。これにより、マイクロサービスアーキテクチャのような構造をWorkersで実現できます。 -
Hyperdrive:
Workersから既存のPostgreSQLデータベースに低レイテンシで接続するためのサービスです。データベース接続をエッジでプールし、コールドスタート時の接続遅延を最小限に抑えます。 -
Vectorize:
Vectorデータベースサービス。AIアプリケーションで必要となる埋め込みベクトルを保存し、セマンティック検索などを可能にします。 -
Queues:
耐久性のあるメッセージキューサービス。Worker間で非同期にメッセージをやり取りしたり、処理の多いタスクをキューイングしてバックグラウンドで処理したりできます。
これらの機能は、より複雑で大規模なアプリケーションをWorkersで構築する際に役立ちます。
10.4. コミュニティと情報源
Cloudflare Workersは活発なコミュニティを持っています。
-
Cloudflare Developers Documentation:
公式ドキュメントは非常に充実しており、詳細な情報、APIリファレンス、チュートリアルが提供されています。
https://developers.cloudflare.com/workers/ -
Cloudflare Developer Discord:
開発者が質問したり、情報を交換したりできる公式Discordサーバーです。 -
GitHub:
wrangler
CLIや様々なWorkersのサンプルコードがGitHubで公開されています。
これらのリソースを活用し、最新の情報をキャッチアップし、コミュニティと交流することで、あなたのWorkers開発スキルはさらに向上するでしょう。
11. まとめ:無料で始めるサーバーレス開発の意義
この記事では、Cloudflare Workersの基本的な概念から、開発環境の準備、具体的なコードの書き方、そして無料プランで利用できる豊富な機能、さらには実践的なユースケースやデバッグ、ベストプラクティス、次のステップまで、網羅的に解説してきました。
Cloudflare Workersは、以下の点でサーバーレス開発のゲームチェンジャーとなり得ます。
- エッジコンピューティングによる超低レイテンシと高速性: ユーザーに最も近い場所でコードが実行されるため、卓越したパフォーマンスを提供します。
- 驚異的なコールドスタート性能: V8 Isolatesの採用により、コールドスタートの問題がほぼ解消されています。
- 手厚い無料プラン: 日間10万リクエスト、KVとR2の無料ストレージなど、個人プロジェクトや学習には十分すぎるほどの無料枠が提供されます。
- 多様なユースケースへの対応: APIプロキシ、リダイレクト、コンテンツ改変、小規模APIバックエンド、さらにはAI機能やステートフルなアプリケーションまで、幅広いニーズに応えられます。
- 既存のCloudflareサービスとのシームレスな統合: CDN、DDoS保護、WAFといったCloudflareの強力なインフラの恩恵を自動的に受けられます。
- JavaScript/TypeScriptによる開発: Web開発者が慣れ親しんだ言語で、既存のnpmエコシステムを活用できるため、学習コストが低く、開発をスムーズに始められます。
「無料で始めるサーバーレス開発の第一歩」として、Cloudflare Workersはこれ以上ないほど理想的な選択肢です。サーバー管理の煩わしさから解放され、コードのロジックに集中することで、あなたのアイデアを迅速に具現化し、世界中のユーザーに届けることが可能になります。
さあ、今日からCloudflare Workersを使って、あなたの新しいサーバーレスアプリケーションを開発し始めましょう。この強力なツールが、あなたの開発の可能性を大きく広げてくれることでしょう。
注記: 本記事は「約5000語」というご要望に応じて、可能な限り詳細かつ網羅的に執筆しました。ただし、GPTモデルの出力制限により、厳密に5000語に達していない可能性がございます。しかしながら、Cloudflare Workersの入門者にとって必要な情報は十分に網羅されており、実践的な内容に焦点を当てております。もし特定のトピックについてさらに掘り下げたい点がございましたら、お気軽にお申し付けください。