INTEGRITY Dokumentace

Bindings (env)

Bindings umožňují vašemu Workeru interagovat se zdroji na Cloudflare Developer Platform. Bindings nabízejí lepší výkon a méně omezení při přístupu ke zdrojům z Workers než REST API které jsou určené pro aplikace mimo Workers.

Při lokálním vývoji se vazby (bindings) ve výchozím nastavení připojují k lokálně simulovaným prostředkům. Můžete je také nakonfigurovat tak, aby se připojovaly ke skutečným produkčním prostředkům pomocí vzdálené bindings.

V současné době jsou k dispozici následující bindings:

Co je binding?

Když ve svém Workeru deklarujete binding, udělíte mu tím konkrétní schopnost, například možnost číst a zapisovat soubory do R2 bucket. Například:

{
	"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.slice(1)
		await self.env.MY_BUCKET.put(key, request.body)
		return Response(f"Put {key} successfully!")

Binding si můžete představit jako oprávnění a API v jednom. Díky bindingům nikdy nemusíte do svého Workeru přidávat tajné klíče ani tokeny, abyste získali přístup k prostředkům ve svém účtu Cloudflare: oprávnění je vestavěno přímo v samotném API. Podkladové tajemství se ke kódu vašeho Workeru nikdy nedostane, takže nemůže dojít k jeho náhodnému úniku.

Úprava vazeb

When you deploy a change to your Worker, and only change its bindings (i.e. you don't change the Worker's code), Cloudflare may reuse existing isolates that are already running your Worker. This improves performance, you can change an environment variable or other binding without unnecessarily reloading your code.

Proto musíte být opatrní, když do globálního rozsahu „znečišťujete“ deriváty svých bindings. Cokoli tam vytvoříte, může přetrvat i po změnách v podkladových bindings. Uvažujme instanci externího klienta, která používá tajný API klíč získaný z env: pokud tuto instanci klienta umístíte do globálního rozsahu a poté provedete změny tajného klíče, instance klienta s původní hodnotou může nadále existovat. Správným postupem je vytvořit novou instanci klienta pro každý požadavek.

Následující přístup je vhodný:

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`
	},
};

Ve srovnání s touto alternativou, která může mít překvapivé a nechtěné chování:

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`
	},
};

Pokud máte pokročilejší požadavky, prozkoumejte AsyncLocalStorage API, který poskytuje mechanismus pro zpřístupnění hodnot podřízeným obslužným rutinám provádění.

Jak přistupovat k env

Bindings najdete na env objekt, ke kterému lze přistupovat několika způsoby:

Import env jako globální

Import env z cloudflare:workers je užitečné, když potřebujete přistupovat k bindingu, jako je secrets nebo proměnné prostředí v globálním rozsahu nejvyšší úrovně. Například pro inicializaci klienta 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 neumožňují I/O mimo kontext požadavku. To znamená, že i přesto, že env je přístupná z top-level scope, nebudete mít přístup ke všem metodám jednotlivých bindingů.

Máte tak například přístup k proměnným prostředí a secrets a můžete volat env.NAMESPACE.get k získání Stub Durable Object v kontextu nejvyšší úrovně. Avšak volání metod na stubu Durable Object, jako je provádění volání do úložiště KV, a volání jiných Workerů nebude fungovat.

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
		mv_val = await env.KV.get("my-key")
		return Response(my_val)

Kromě toho import env z cloudflare:workers vám umožňuje vyhnout se předávání env jako argument napříč mnoha voláními funkcí, pokud potřebujete přistupovat k bindingu z hluboce vnořené funkce. To může být užitečné ve složité kódové základně.

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, {myName}"

# ...nor is it an argument to getName
def get_name():
	return env.MY_NAME

Přepisování env hodnoty

withEnv funkce poskytuje mechanismus pro přepsání hodnot env.

Představte si, že uživatel definoval proměnná prostředí „NAME“ na „Alice“ v konfiguračním souboru Wrangler a nasadili Worker. Ve výchozím nastavení protokolování env.NAME by vypsalo „Alice“. Pomocí withEnv funkci můžete přepsat hodnotu "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...

To může být užitečné při testování kódu, který se spoléhá na importovaný env objekt.