ch04-bindings
在 GitHub 上檢視·5 個檔案·2.6 KB
取得並執行
這個範例可以獨立 clone 執行,不依賴其他章節。
npx degit mrsuner/cloudflare-serverless-platform-manuals/examples/ch04-bindings
cd ch04-bindings
npm install可用指令
npm run dev # wrangler dev
npm run deploy # wrangler deploy
npm run typecheck # tsc --noEmit
npm run cf-typegen # wrangler types --env-interface CloudflareBindings說明
ch04 — Binding probe
Section titled “ch04 — Binding probe”Companion example for docs/04-bindings.md.
Exercises four bindings people rarely see in tutorials — ratelimits,
version_metadata, secrets.required — plus the two ways to reach env.
npm installecho 'API_KEY="local-dev-key"' > .dev.varsnpm run cf-typegennpm run devVerified behaviour
Section titled “Verified behaviour”2026-07-28 · wrangler@4.114.0 · workerd@1.20260722.1
The two env objects are not the same object
Section titled “The two env objects are not the same object”$ curl -s localhost:8787/identity{"sameObject":false, "topLevelKeys":["API_KEY","APP_NAME","CACHE","LIMITER","PUBLIC_URL","VERSION"], "handlerKeys": ["API_KEY","APP_NAME","CACHE","LIMITER","PUBLIC_URL","VERSION"]}Same keys, different identity. import { env } from "cloudflare:workers"
is not an alias for the handler parameter.
process.env exists only with nodejs_compat — and carries secrets
Section titled “process.env exists only with nodejs_compat — and carries secrets”Default config (flag off):
$ curl -s localhost:8787/procenv{"hasProcess":false,"appName":null,"apiKey":null}Uncomment "compatibility_flags": ["nodejs_compat"] in wrangler.jsonc:
$ curl -s localhost:8787/procenv{"hasProcess":true,"appName":"ch04-bindings","apiKey":"<present>"}API_KEY is a secret from .dev.vars, and it is now readable by any
dependency in the bundle. Enabling nodejs_compat changes your secret
exposure surface.
The rate limit binding works locally
Section titled “The rate limit binding works locally”{ "simple": { "limit": 5, "period": 10 } }:
$ for i in $(seq 7); do curl -s -o /dev/null -w "%{http_code} " localhost:8787/limit; done200 200 200 200 200 429 429No KV, no Durable Object, no external service.
version_metadata
Section titled “version_metadata”$ curl -s localhost:8787/version{"version":{"id":"19cc8aac-1016-4c42-9f66-acc9d6283610","tag":"", "timestamp":"2026-07-28T04:56:31.361Z"}}secrets.required generates types on its own
Section titled “secrets.required generates types on its own”With .dev.vars deleted, wrangler types still emits:
interface __BaseEnv_CloudflareBindings { CACHE: KVNamespace; LIMITER: RateLimit; VERSION: WorkerVersionMetadata; APP_NAME: "ch04-bindings"; PUBLIC_URL: "https://example.com"; API_KEY: string; // from secrets.required alone}Not verified here: enforcement at real deploy time. --dry-run does not
check it, since that requires querying the account’s stored secrets.
A missing binding is undefined, not an error
Section titled “A missing binding is undefined, not an error”$ curl -s localhost:8787/missing{"value":null}Combined with named environments not inheriting bindings (chapter 02), this is the most common cause of a staging Worker that deploys green and then throws on its first real request.
The authoritative binding catalogue
Section titled “The authoritative binding catalogue”Not the docs — Wrangler’s own schema:
jq '.properties | keys' node_modules/wrangler/config-schema.json原始碼
wrangler.jsonc
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "ch04-bindings",
"main": "src/index.ts",
"compatibility_date": "2026-07-24",
"compatibility_flags": ["nodejs_compat"],
"observability": { "enabled": true },
"vars": { "APP_NAME": "ch04-bindings", "PUBLIC_URL": "https://example.com" },
"kv_namespaces": [{ "binding": "CACHE", "id": "0000000000000000000000000000aaaa" }],
"version_metadata": { "binding": "VERSION" },
"ratelimits": [{ "name": "LIMITER", "namespace_id": "1001", "simple": { "limit": 5, "period": 10 } }],
"secrets": { "required": ["API_KEY"] }
}package.json
{ "name": "ch04-bindings", "private": true, "type": "module",
"scripts": { "dev": "wrangler dev", "deploy": "wrangler deploy", "typecheck": "tsc --noEmit",
"cf-typegen": "wrangler types --env-interface CloudflareBindings" },
"devDependencies": { "typescript": "^5.9.0", "wrangler": "^4.114.0" } }src/index.ts
import { env as topLevelEnv } from "cloudflare:workers";
// `process` only exists when nodejs_compat is enabled. Probe it safely.
const proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;
export default {
async fetch(request: Request, env: CloudflareBindings, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
switch (url.pathname) {
case "/identity":
return Response.json({
sameObject: (topLevelEnv as unknown) === (env as unknown),
topLevelKeys: Object.keys(topLevelEnv).sort(),
handlerKeys: Object.keys(env).sort(),
});
case "/procenv":
return Response.json({
hasProcess: proc !== undefined,
appName: proc?.env?.APP_NAME ?? null,
apiKey: proc?.env?.API_KEY ? "<present>" : null,
});
case "/version":
return Response.json({ version: env.VERSION });
case "/limit": {
const { success } = await env.LIMITER.limit({ key: "demo" });
return Response.json({ success }, { status: success ? 200 : 429 });
}
case "/missing":
return Response.json({
value: (env as unknown as Record<string, unknown>).DOES_NOT_EXIST ?? null,
});
default:
return new Response("try /identity /procenv /version /limit /missing\n", { status: 404 });
}
},
} satisfies ExportedHandler<CloudflareBindings>;.dev.vars.example
API_KEY="local-dev-key"tsconfig.json
{ "compilerOptions": { "target": "esnext", "lib": ["esnext"], "module": "esnext",
"moduleResolution": "bundler", "types": ["./worker-configuration.d.ts"],
"strict": true, "skipLibCheck": true, "noEmit": true, "isolatedModules": true },
"include": ["src/**/*.ts", "worker-configuration.d.ts"] }