INTEGRITY Документация

Контекст (ctx)

Context API предоставляет методы для управления жизненным циклом вашего Worker или Durable Object.

Контекст доступен в следующих местах:

Обратите внимание, что Context API доступен исключительно в контекстах без сохранения состояния, то есть не Durable Objects. Однако у Durable Objects есть другой объект, Состояние Durable Object, который доступен как this.ctx внутри класса Durable Object и предоставляет часть той же функциональности, что и Context API.

props

ctx.props предоставляет способ передачи дополнительной конфигурации Worker в зависимости от контекста его вызова. Например, если ваш Worker вызывается другим Worker, ctx.props может предоставлять информацию о вызывающем worker.

Например, представьте, что вы настраиваете Worker с именем "frontend-worker", которому нужно взаимодействовать с другим Worker с именем "doc-worker" для работы с документами. Вы можете настроить "frontend-worker" с Service Binding например:

{
	"services": [
		{
			"binding": "DOC_SERVICE",
			"service": "doc-worker",
			"entrypoint": "DocServiceApi",
			"props": {
				"clientId": "frontend-worker",
				"permissions": [
					"read",
					"write"
				]
			}
		}
	]
}
[[services]]
binding = "DOC_SERVICE"
service = "doc-worker"
entrypoint = "DocServiceApi"

  [services.props]
  clientId = "frontend-worker"
  permissions = [ "read", "write" ]

Теперь frontend-worker может обращаться к doc-worker с помощью кода вида env.DOC_SERVICE.getDoc(id). Это выполнит Удалённый вызов процедур при вызове метода getDoc() класса DocServiceApi, WorkerEntrypoint класс экспортируется doc-worker.

Конфигурация содержит props значение. Это произвольное значение JSON. Когда DOC_SERVICE привязка используется, DocServiceApi экземпляр, получающий вызов, сможет получить доступ к этому props значение как this.ctx.props. Здесь настроено props чтобы указать, что вызов исходит от frontend-worker и что ему разрешено читать и записывать документы. Однако содержимое props может быть любым.

Платформа Workers спроектирована так, чтобы гарантировать, что ctx.props может задать только пользователь с правами на редактирование и развёртывание worker, для которого это предназначено. Это означает, что вы можете доверять содержимому ctx.props является подлинным. Нет необходимости использовать секретные ключи или криптографические подписи в ctx.props значение.

ctx.props также можно использовать для настройки интерфейса RPC, представляющего конкретный ресурс, тем самым создавая «пользовательскую привязку» (custom binding). Например, можно настроить Service Binding к нашему «doc-worker», который предоставляет доступ только к определённому документу:

{
	"services": [
		{
			"binding": "FOO_DOCUMENT",
			"service": "doc-worker",
			"entrypoint": "DocumentApi",
			"props": {
				"docId": "e366592caec1d88dff724f74136b58b5",
				"permissions": [
					"read",
					"write"
				]
			}
		}
	]
}
[[services]]
binding = "FOO_DOCUMENT"
service = "doc-worker"
entrypoint = "DocumentApi"

  [services.props]
  docId = "e366592caec1d88dff724f74136b58b5"
  permissions = [ "read", "write" ]

Здесь мы разместили docId свойство в ctx.props. DocumentApi класс можно спроектировать так, чтобы он предоставлял API для конкретного документа, идентифицируемого ctx.props.docId, и обеспечивая соблюдение заданных разрешений.

exports

ctx.exports предоставляет автоматически настроенные обратные ("loopback") привязки для всех ваших экспортов верхнего уровня.

Например:

import { WorkerEntrypoint } from "cloudflare:workers";

export class Greeter extends WorkerEntrypoint {
	greet(name) {
		return `Hello, ${name}!`;
	}
}

export default {
	async fetch(request, env, ctx) {
		let greeting = await ctx.exports.Greeter.greet("World");
		return new Response(greeting);
	},
};

В этом примере обработчик fetch по умолчанию вызывает Greeter класс по RPC, аналогично тому, как вы бы использовали Service Binding. Однако никакой внешней настройки не требуется. ctx.exports заполняется автоматически из импортов верхнего уровня.

Указание ctx.props при использовании ctx.exports

Loopback Service Bindings в ctx.exports обладают дополнительной возможностью, недоступной обычным Service Binding: вызывающая сторона может указать значение ctx.props который должен быть доставлен вызываемой стороне.

import { WorkerEntrypoint } from "cloudflare:workers";

export class Greeter extends WorkerEntrypoint {
	greet(name) {
		return `${this.ctx.props.greeting}, ${name}!`;
	}
}

export default {
	async fetch(request, env, ctx) {
		// Make a custom greeter that uses the greeting "Welcome".
		let greeter = ctx.exports.Greeter({ props: { greeting: "Welcome" } });

		// Greet the world. Returns "Welcome, World!"
		let greeting = await greeter.greet("World");

		return new Response(greeting);
	},
};
import { WorkerEntrypoint } from "cloudflare:workers";

type Props = {
	greeting: string;
};

export class Greeter extends WorkerEntrypoint<Env, Props> {
	greet(name) {
		return `${this.ctx.props.greeting}, ${name}!`;
	}
}

export default {
	async fetch(request, env, ctx) {
		// Make a custom greeter that uses the greeting "Welcome".
		let greeter = ctx.exports.Greeter({ props: { greeting: "Welcome" } });

		// Greet the world. Returns "Welcome, World!"
		let greeting = await greeter.greet("World");

		return new Response(greeting);
	},
} satisfies ExportedHandler<Env>;

Указывать props динамически в этом случае можно, поскольку вызывает тот же Worker, а значит, ему можно доверить указание любых props. Возможность настраивать props особенно полезна, когда итоговая привязка передаётся другому Worker через RPC или используется в env для динамически загружаемый worker.

Обратите внимание, что props значения, указанные таким образом, могут содержать любой тип, допускающий "постоянную" сериализацию. Сюда входят все базовые типы данных, поддерживающие структурное клонирование. Сюда же входят и сами Service Bindings: вы можете разместить Service Binding в props другого Service Binding.

Типы TypeScript для ctx.exports и ctx.props

При использовании TypeScript следует использовать wrangler types команда чтобы автоматически генерировать типы для вашего проекта. Сгенерированные типы обеспечат ctx.exports типизирован правильно.

При объявлении класса точки входа (entrypoint), принимающего props, обязательно объявите его как extends WorkerEntrypoint<Env, Props>, где Props это тип ctx.props. См. пример выше.

tracing

ctx.tracing предоставляет доступ к API для пользовательских спанов для создания пользовательских спанов трассировки (trace span). Это тот же объект, что доступен через import { tracing } from "cloudflare:workers".

Трассировка должна быть включена в вашем Worker, чтобы спаны записывались.

export default {
	async fetch(request, env, ctx) {
		return ctx.tracing.enterSpan("handleRequest", async (span) => {
			span.setAttribute("url.path", new URL(request.url).pathname);
			const data = await env.MY_KV.get("key");
			return new Response(data);
		});
	},
};

Полное описание API см. в Пользовательские спаны.

waitUntil

ctx.waitUntil() продлевает время жизни вашего Worker, позволяя выполнять работу, не блокируя возврат ответа, и которая может продолжаться после того, как ответ уже отправлен. Он принимает Promise, которое Workers runtime продолжит выполнять даже после того, как ответ уже возвращён обработчиком Worker обработчик.

Используйте ctx.waitUntil() для работы, которая может выполняться после отправки ответа, например логирования, аналитики или записи в кеш, при условии что она завершится в течение waitUntil() ограничение по времени. Если клиент всё ещё получает ответ, включая потоковое тело ответа, вызов Worker остаётся активным без учёта ctx.waitUntil(). Если ваш ответ зависит от результата работы, await работу перед возвратом ответа либо передавать ответ потоково по мере её выполнения.

waitUntil обычно используется для:

Можно вызвать waitUntil() несколько раз. Аналогично Promise.allSettled, даже если promise, переданный в один waitUntil вызов отклоняется, промисы, переданные другим waitUntil() вызовы продолжат выполняться.

Например:

export default {
	async fetch(request, env, ctx) {
		// Forward / proxy original request
		let res = await fetch(request);

		// Add custom header(s)
		res = new Response(res.body, res);
		res.headers.set("x-foo", "bar");

		// Cache the response
		// NOTE: Does NOT block / wait
		ctx.waitUntil(caches.default.put(request, res.clone()));

		// Done
		return res;
	},
};

passThroughOnException

passThroughOnException метод позволяет Worker fail open, и передавать запрос на исходный сервер, если Worker выбрасывает необработанное исключение. Это удобно, когда Workers используется как слой перед существующим сервисом: сервис за Worker сможет сам обрабатывать непредвиденные ошибки, возникающие в вашем Worker.

export default {
	async fetch(request, env, ctx) {
		ctx.passThroughOnException();

		try {
			return await fetch(request);
		} catch (error) {
			console.error("Origin fetch failed", error);
			return new Response("Bad Gateway", { status: 502 });
		}
	},
};