← Cloudflare Workers / workers / runtime-apis
Привязки (env)
Привязки позволяют вашему Worker взаимодействовать с ресурсами Cloudflare Developer Platform. При обращении к ресурсам из Workers привязки обеспечивают более высокую производительность и меньше ограничений по сравнению с REST API которые предназначены для приложений, не связанных с Workers.
Во время локальной разработки привязки по умолчанию подключаются к локально симулируемым ресурсам. Вы также можете настроить их для подключения к реальным продакшен-ресурсам с помощью удаленные привязки.
На данный момент доступны следующие привязки:
- AI
- Analytics Engine
- Assets
- Browser Run
- D1
- Диспетчер (Workers for Platforms)
- Durable Objects
- Dynamic Worker Loaders
- Переменные окружения
- Hyperdrive
- Изображения
- KV
- Media Transformations
- mTLS
- Queues
- R2
- Rate Limiting
- Секреты
- Secrets Store
- Service bindings
- Stream
- Vectorize
- Метаданные версии
- Workflows
Что такое привязка?
Объявляя binding в 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!")Binding можно представить как разрешение и API в одном целом. Благодаря bindings вам никогда не придётся добавлять в Worker секретные ключи или токены для доступа к ресурсам вашего аккаунта Cloudflare: разрешение встроено прямо в сам API. Базовый секрет никогда не передаётся в код Worker, поэтому его невозможно случайно раскрыть.
Изменение привязок
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.
Поэтому будьте осторожны, когда «загрязняете» глобальную область видимости производными от ваших привязок. Всё, что вы там создадите, может продолжить существовать даже после изменений в базовых привязках. Рассмотрим экземпляр внешнего клиента, который использует секретный API ключ, полученный из env: если поместить этот экземпляр клиента в глобальную область видимости, а затем изменить секрет, экземпляр клиента со старым значением может продолжить существовать. Правильный подход: создавать новый экземпляр клиента для каждого запроса.
Вот пример удачного подхода:
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}`); }, };
-
Это свойство класса в 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}")
Импорт env как глобальный
Импорт env от cloudflare:workers полезен, когда вам нужно обратиться к привязке,
например к секреты или переменные окружения
в глобальной области верхнего уровня. Например, для инициализации клиента 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 не допускают операции ввода-вывода за пределами контекста запроса. Это означает, что даже
хотя env доступен из области видимости верхнего уровня, вы не сможете обращаться
ко всем методам binding.
Например, переменные окружения и секреты доступны, и вы можете
вызвать env.NAMESPACE.get чтобы получить Durable Object stub в
контексте верхнего уровня. Однако вызов методов на заглушке 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
mv_val = await env.KV.get("my-key")
return Response(my_val)Кроме того, импорт env от cloudflare:workers позволяет не передавать 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.
Предположим, пользователь определил переменная окружения
«NAME» на «Alice» в файле конфигурации Wrangler и развернул 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 объект.