バインディングを使うと、Worker から Cloudflare Developer Platform 上のリソースと連携できます。Workers からリソースへアクセスする場合、非 Workers アプリ向けの REST API より、バインディングの方が性能が良く、制限も少なくなります。
ローカル開発では、バインディングはデフォルトでローカルにシミュレートされたリソースへ接続します。リモートバインディング を使うと、本番の実リソースへ接続するよう設定できます。
現在利用できるバインディングは次のとおりです。
- AI
- Analytics Engine
- Assets
- Browser Run
- D1
- Dispatcher(Workers for Platforms)
- Durable Objects
- Dynamic Worker Loaders
- Hyperdrive
- Images
- KV
- Media Transformations
- mTLS
- Queues
- R2
- Secrets Store
- Service bindings
- Stream
- Vectorize
- Workflows
- シークレット
- バージョンメタデータ
- レート制限
- 環境変数
Worker にバインディングを宣言すると、たとえば R2 バケットへのファイルの読み書きといった、特定の能力を付与します。例:
{
"main": "./src/index.js",
"r2_buckets": [
{
"binding": "MY_BUCKET",
"bucket_name": "<MY_BUCKET_NAME>"
}
]
}main = "./src/index.js"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "<MY_BUCKET_NAME>"export default {
async fetch(request, env) {
const url = new URL(request.url);
const key = url.pathname.slice(1);
await env.MY_BUCKET.put(key, request.body);
return new Response(`Put ${key} successfully!`);
},
};from workers import WorkerEntrypoint, Response
from urllib.parse import urlparse
class Default(WorkerEntrypoint):
async def fetch(self, request):
url = urlparse(request.url)
key = url.path[1:]
await self.env.MY_BUCKET.put(key, request.body)
return Response(f"Put {key} successfully!")バインディングは、権限と API が一体になったものと考えると分かります。バインディングを使えば、Cloudflare アカウント上のリソースへアクセスするために、シークレットキーやトークンを Worker に足す必要はありません。権限は API 自体に埋め込まれています。裏にあるシークレットが Worker のコードに露出することはなく、誤って漏れることもありません。
Worker をデプロイするとき、変更がバインディングだけ(つまり Worker のコードは変えない)なら、Cloudflare はすでにその Worker を動かしている既存のアイソレートを再利用することがあります。性能が上がります。環境変数やその他のバインディングを、コードを不要に再読み込みせずに変更できます。
そのため、バインディングから派生した値でグローバルスコープを「汚染」しないよう注意してください。そこに作ったものは、裏のバインディングを変えても残り続けることがあります。env から取得したシークレット API キーを使う外部クライアントインスタンスを考えてください。このクライアントをグローバルスコープに置き、その後シークレットを変えても、元の値を使うクライアントが残り続けることがあります。正しい方法は、リクエストごとに新しいクライアントインスタンスを作ることです。
次の書き方が適切です。
export default {
fetch(request, env) {
let client = new Client(env.MY_SECRET); // `client` is guaranteed to be up-to-date with the latest value of `env.MY_SECRET` since a new instance is constructed with every incoming request
// ... do things with `client`
},
};次の代替は、意外で望ましくない挙動になることがあります。
let client = undefined;
export default {
fetch(request, env) {
client ??= new Client(env.MY_SECRET); // `client` here might not be updated when `env.MY_SECRET` changes, since it may already exist in global scope
// ... do things with `client`
},
};より高度な要件がある場合は AsyncLocalStorage API を検討してください。子の実行ハンドラーへ値を渡す仕組みを提供します。
バインディングは env オブジェクト上にあり、次の方法でアクセスできます。
-
fetchなどのエントリポイントハンドラーの引数です。export default { async fetch(request, env) { return new Response(`Hi, ${env.NAME}`); }, };
-
WorkerEntrypoint、 DurableObject、Workflow のクラスプロパティです。
export class MyDurableObject extends DurableObject { async sayHello() { return `Hi, ${this.env.NAME}!`; } }from workers import WorkerEntrypoint, Response class Default(WorkerEntrypoint): async def fetch(self, request): return Response(f"Hi {self.env.NAME}") -
cloudflare:workersからインポートできます。import { env } from "cloudflare:workers"; console.log(`Hi, ${env.NAME}`);from workers import env print(f"Hi, {env.NAME}")
cloudflare:workers から env をインポートすると、トップレベルのグローバルスコープで
Secrets や 環境変数
などのバインディングにアクセスできます。たとえば API クライアントの初期化です。
import { env } from "cloudflare:workers";
import ApiClient from "example-api-client";
// API_KEY and LOG_LEVEL now usable in top-level scope
let apiClient = ApiClient.new({ apiKey: env.API_KEY });
const LOG_LEVEL = env.LOG_LEVEL || "info";
export default {
fetch(req) {
// you can use apiClient or LOG_LEVEL, configured before any request is handled
},
};from workers import WorkerEntrypoint, env
from example_api_client import ApiClient
api_client = ApiClient(api_key=env.API_KEY)
LOG_LEVEL = getattr(env, "LOG_LEVEL", "info")
class Default(WorkerEntrypoint):
async def fetch(self, request):
# ...Workers は、リクエストコンテキストの外からの I/O を許可しません。そのため
env はトップレベルスコープからアクセスできても、すべてのバインディングのメソッドを
呼べるわけではありません。
たとえば環境変数と Secrets にはアクセスでき、トップレベルコンテキストで
env.NAMESPACE.get を呼んで Durable Object スタブ を取得することもできます。
ただし、Durable Object スタブ上のメソッド呼び出し、KV ストアへの呼び出し、
ほかの Workers への呼び出し は動きません。
import { env } from "cloudflare:workers";
// This would error!
// env.KV.get('my-key')
export default {
async fetch(req) {
// This works
let myVal = await env.KV.get("my-key");
Response.new(myVal);
},
};from workers import Response, WorkerEntrypoint, env
# This would fail!
# env.KV.get('my-key')
class Default(WorkerEntrypoint):
async def fetch(self, request):
# This works
my_val = await env.KV.get("my-key")
return Response(my_val)加えて、cloudflare:workers から env をインポートすると、深く入れ子になった関数から
バインディングへアクセスするときに、多くの関数呼び出しへ env を引数として渡さずに済みます。
複雑なコードベースでは便利です。
import { env } from "cloudflare:workers";
export default {
fetch(req) {
Response.new(sayHello());
},
};
// env is not an argument to sayHello...
function sayHello() {
let myName = getName();
return `Hello, ${myName}`;
}
// ...nor is it an argument to getName
function getName() {
return env.MY_NAME;
}from workers import Response, WorkerEntrypoint, env
class Default(WorkerEntrypoint):
def fetch(req):
return Response(say_hello())
# env is not an argument to say_hello...
def say_hello():
my_name = get_name()
return f"Hello, {my_name}"
# ...nor is it an argument to getName
def get_name():
return env.MY_NAMEwithEnv 関数は、env の値を上書きする仕組みを提供します。
ユーザーが Wrangler 設定ファイルで 環境変数
「NAME」を「Alice」と定義し、Worker をデプロイしたとします。デフォルトでは env.NAME を
ログすると「Alice」と出ます。withEnv 関数を使うと、「NAME」の値を上書きできます。
import { env, withEnv } from "cloudflare:workers";
function logName() {
console.log(env.NAME);
}
export default {
fetch(req) {
// this will log "Alice"
logName();
withEnv({ NAME: "Bob" }, () => {
// this will log "Bob"
logName();
});
// ...etc...
},
};from workers import Response, WorkerEntrypoint, env, patch_env
def log_name():
print(env.NAME)
class Default(WorkerEntrypoint):
async def fetch(req):
# this will log "Alice"
log_name()
with patch_env(NAME="Bob"):
# this will log "Bob"
log_name()
# ...etc...インポートした env オブジェクトに依存するコードのテストで役立ちます。