← Sandbox SDK / sandbox / api
Порты
Публикуйте сервисы, запущенные в вашей песочнице, через публичные preview URL. См. Концепция Preview URL для получения подробностей.
Функции модуля
proxyToSandbox()
Направляет входящие HTTP- и WebSocket-запросы в нужный контейнер песочницы. Вызывайте это в начале вашего Worker fetch обработчик, до какой-либо логики приложения, чтобы он автоматически перехватывал и перенаправлял запросы preview URL.
proxyToSandbox(request: Request, env: Env): Promise<Response | null>Параметры:
request- ВходящийRequestобъект изfetchобработчик.env-Envобъект, содержащий вашу привязку Sandbox.
Возвращает: Promise<Response | null>, это Response если запрос совпал с preview URL и был направлен в сандбокс, или null если запрос не совпал и должен обрабатываться логикой вашего приложения.
Функция проверяет имя хоста запроса, чтобы определить, соответствует ли оно шаблону поддомена открытого порта (например, 8080-sandbox-id-token.yourdomain.com). Если совпадает, proxyToSandbox() проксирует запрос к нужному Durable Object, а сервис sandbox его обрабатывает. Поддерживаются как HTTP, так и запросы обновления соединения WebSocket.
import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request, env) {
// Always call proxyToSandbox first to handle preview URL requests
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
// ...
return new Response("Not found", { status: 404 });
},
};import { proxyToSandbox, getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Always call proxyToSandbox first to handle preview URL requests
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
// ...
return new Response('Not found', { status: 404 });
}
};Методы
exposePort()
Откройте порт и получите preview URL для доступа к сервисам, запущенным в песочнице.
const response = await sandbox.exposePort(port: number, options: ExposePortOptions): Promise<ExposePortResponse>Параметры:
port- Номер порта для открытия (1024-65535)options:hostname- Доменное имя вашего Worker (например,'example.com'). Требуется для построения preview URL с wildcard-поддоменами видаhttps://8080-sandbox-abc123token.example.com. Не может быть.workers.devдомен, поскольку он не поддерживает wildcard-шаблоны DNS.name- Понятное имя порта (необязательно)token- Пользовательский токен для URL-адреса предварительного просмотра (необязательно). Должен содержать от 1 до 16 символов и включать только строчные буквы (a-z), цифры (0-9), дефисы (-) и символы подчеркивания (_). Если он не указан, автоматически генерируется случайный 16-символьный токен.
Возвращает: Promise<ExposePortResponse> с port, url (preview URL), name
// Extract hostname from request
const { hostname } = new URL(request.url);
// Basic usage with auto-generated token
await sandbox.startProcess("python -m http.server 8000");
const exposed = await sandbox.exposePort(8000, { hostname });
console.log("Available at:", exposed.url);
// https://8000-sandbox-id-abc123random.yourdomain.com
// With custom token for stable URLs across restarts
const stable = await sandbox.exposePort(8080, {
hostname,
token: "my_service_v1", // 1-16 chars: a-z, 0-9, _
});
console.log("Stable URL:", stable.url);
// https://8080-sandbox-id-my_service_v1.yourdomain.com
// With custom token for stable URLs across deployments
await sandbox.startProcess("node api.js");
const api = await sandbox.exposePort(3000, {
hostname,
name: "api",
token: "prod-api-v1", // URL stays same across restarts
});
console.log("Stable API URL:", api.url);
// https://3000-sandbox-id-prod-api-v1.yourdomain.com
// Multiple services with custom tokens
await sandbox.startProcess("npm run dev");
const frontend = await sandbox.exposePort(5173, {
hostname,
name: "frontend",
token: "dev-ui",
});// Extract hostname from request
const { hostname } = new URL(request.url);
// Basic usage with auto-generated token
await sandbox.startProcess('python -m http.server 8000');
const exposed = await sandbox.exposePort(8000, { hostname });
console.log('Available at:', exposed.url);
// https://8000-sandbox-id-abc123random.yourdomain.com
// With custom token for stable URLs across restarts
const stable = await sandbox.exposePort(8080, {
hostname,
token: 'my_service_v1' // 1-16 chars: a-z, 0-9, _
});
console.log('Stable URL:', stable.url);
// https://8080-sandbox-id-my_service_v1.yourdomain.com
// With custom token for stable URLs across deployments
await sandbox.startProcess('node api.js');
const api = await sandbox.exposePort(3000, {
hostname,
name: 'api',
token: 'prod-api-v1' // URL stays same across restarts
});
console.log('Stable API URL:', api.url);
// https://3000-sandbox-id-prod-api-v1.yourdomain.com
// Multiple services with custom tokens
await sandbox.startProcess('npm run dev');
const frontend = await sandbox.exposePort(5173, {
hostname,
name: 'frontend',
token: 'dev-ui'
});Пользовательские токены для стабильных URL
Пользовательские токены обеспечивают стабильные URL предварительного просмотра при перезапусках контейнера и повторных развёртываниях. Это полезно в следующих случаях:
- Продакшен-среды - Делитесь стабильными URL с пользователями или командами
- Рабочие процессы разработки - Поддерживайте закладки и интеграции
- Конвейеры CI/CD - Используйте постоянные URL в тестах или скриптах развёртывания
Требования к токену:
- длина от 1 до 16 символов
- Только строчные буквы (a-z), цифры (0-9), дефисы (-) и символы подчёркивания (_)
- Должно быть уникальным для каждой песочницы (нельзя использовать один токен для разных портов)
// Production API with stable URL
const { url } = await sandbox.exposePort(8080, {
hostname: "api.example.com",
token: "v1-stable", // Always the same URL
});
// Error: Token collision prevention
await sandbox.exposePort(8081, { hostname, token: "v1-stable" });
// Throws: Token 'v1-stable' is already in use by port 8080
// Success: Re-exposing same port with same token (idempotent)
await sandbox.exposePort(8080, { hostname, token: "v1-stable" });
// Works - same port, same token// Production API with stable URL
const { url } = await sandbox.exposePort(8080, {
hostname: 'api.example.com',
token: 'v1-stable' // Always the same URL
});
// Error: Token collision prevention
await sandbox.exposePort(8081, { hostname, token: 'v1-stable' });
// Throws: Token 'v1-stable' is already in use by port 8080
// Success: Re-exposing same port with same token (idempotent)
await sandbox.exposePort(8080, { hostname, token: 'v1-stable' });
// Works - same port, same tokenvalidatePortToken()
Проверяет, авторизован ли токен для доступа к определённому открытому порту. Полезно для собственной логики аутентификации или маршрутизации.
const isValid = await sandbox.validatePortToken(port: number, token: string): Promise<boolean>Параметры:
port- Номер порта для проверкиtoken- Токен для проверки
Возвращает: Promise<boolean> - true если токен действителен для порта, false иначе
// Custom validation in your Worker
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Extract token from custom header or query param
const customToken = request.headers.get("x-access-token");
if (customToken) {
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
const isValid = await sandbox.validatePortToken(8080, customToken);
if (!isValid) {
return new Response("Invalid token", { status: 403 });
}
}
// Handle preview URL routing
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
return new Response("Not found", { status: 404 });
},
};// Custom validation in your Worker
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
// Extract token from custom header or query param
const customToken = request.headers.get('x-access-token');
if (customToken) {
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
const isValid = await sandbox.validatePortToken(8080, customToken);
if (!isValid) {
return new Response('Invalid token', { status: 403 });
}
}
// Handle preview URL routing
const proxyResponse = await proxyToSandbox(request, env);
if (proxyResponse) return proxyResponse;
// Your application routes
return new Response('Not found', { status: 404 });
}
};unexposePort()
Удаляет открытый порт и закрывает связанный с ним preview URL.
await sandbox.unexposePort(port: number): Promise<void>Параметры:
port- Номер порта для закрытия
await sandbox.unexposePort(8000);await sandbox.unexposePort(8000);getExposedPorts()
Получение информации обо всех текущих открытых портах.
const response = await sandbox.getExposedPorts(): Promise<GetExposedPortsResponse>Возвращает: Promise<GetExposedPortsResponse> с ports массив (содержащий port, url, name)
const { ports } = await sandbox.getExposedPorts();
for (const port of ports) {
console.log(`${port.name || port.port}: ${port.url}`);
}const { ports } = await sandbox.getExposedPorts();
for (const port of ports) {
console.log(`${port.name || port.port}: ${port.url}`);
}wsConnect()
Подключайтесь к серверам WebSocket, работающим в песочнице. Используйте это, когда вашему Worker нужно установить WebSocket-соединения со службами в песочнице.
Типичные варианты использования:
- Направляет входящие запросы на обновление до WebSocket с пользовательской аутентификацией или авторизацией
- Подключайтесь из своего Worker, чтобы получать данные в реальном времени от сервисов песочницы
Для публикации WebSocket-сервисов через публичные preview-URL используйте exposePort() с proxyToSandbox() вместо этого. См. Руководство по WebSocket-соединениям с примерами.
const response = await sandbox.wsConnect(request: Request, port: number): Promise<Response>Параметры:
request- Входящий запрос на обновление до WebSocketport- Номер порта (1024-65535, кроме 3000)
Возвращает: Promise<Response> - Ответ WebSocket, устанавливающий соединение
import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request, env) {
if (request.headers.get("Upgrade")?.toLowerCase() === "websocket") {
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
return await sandbox.wsConnect(request, 8080);
}
return new Response("WebSocket endpoint", { status: 200 });
},
};import { getSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.headers.get('Upgrade')?.toLowerCase() === 'websocket') {
const sandbox = getSandbox(env.Sandbox, 'my-sandbox');
return await sandbox.wsConnect(request, 8080);
}
return new Response('WebSocket endpoint', { status: 200 });
}
};Дополнительные материалы
- Концепция Preview URL - Как работают preview URL
- Руководство по публикации сервисов - Полный процесс запуска сервисов, открытия портов и маршрутизации запросов
- Руководство по WebSocket-соединениям - Маршрутизация WebSocket через preview URL
- Commands API - Запуск фоновых процессов
- Tunnels API - Не требует настройки
*.trycloudflare.comURL для быстрой разработки