跳转到内容
搜索文档

绑定(env)

最后更新 查看 MarkdownAgent 设置

绑定(binding)允许 Worker 与 Cloudflare Developer Platform 上的资源交互。与面向非 Workers 应用程序的 REST API 相比,从 Workers 访问资源时,绑定提供更好的性能和更少的限制。

在本地开发期间,绑定默认连接到本地模拟资源。您也可以配置它们使用远程绑定(remote bindings) 连接到真实的生产资源。

以下绑定目前可用:

什么是绑定?

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

您可以将绑定视为权限和 API 的结合体。使用绑定时,您永远不必向 Worker 添加密钥或 token 来访问 Cloudflare 账户上的资源——权限嵌入在 API 本身中。底层 secret 永远不会暴露给 Worker 的代码,因此不会意外泄露。

更改绑定

部署 Worker 更改且仅更改其绑定(即不更改 Worker 代码)时,Cloudflare 可能会复用已在运行 Worker 的现有 isolate。这提高了性能——您可以更改环境变量或其他绑定,而无需不必要地重新加载代码。

因此,在全局作用域中"污染"绑定的派生对象时必须小心。尽管您更改了底层绑定,在那里创建的任何内容可能仍会继续存在。考虑一个使用从 env 访问的 secret API 密钥的外部客户端实例:如果将此客户端实例放在全局作用域中然后更改 secret,使用原始值的客户端实例可能仍会继续存在。正确的方法是每个请求创建一个新的客户端实例。

以下是良好的做法:

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

绑定位于 env 对象上,可以通过多种方式访问:

  • 它是入口点处理程序(如 fetch)的参数:

    export default {
    	async fetch(request, env) {
    		return new Response(`Hi, ${env.NAME}`);
    	},
    };
  • 它是 WorkerEntrypointDurableObjectWorkflow 上的类属性:

    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}")

env 作为全局变量导入

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 stub。但是,在 Durable Object stub 上调用方法、调用 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
		mv_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, {myName}"

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

覆盖 env

withEnv 函数提供一种覆盖 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 对象的代码时很有用。

这篇文档对您有帮助吗?