更多使用方法¶
本文整理常见的函数计算云沙箱使用方式,覆盖沙箱生命周期、命令执行、代码解释器、文件系统、Git、动态端口、浏览器自动化、模板查询、VPC、OSS、NAS 等场景。每个场景同时提供 Python 和 TypeScript 示例。
Note
VPC、OSS、NAS 示例需要提前准备对应的阿里云资源,示例中的资源 ID、Bucket、Role ARN 和挂载地址请替换为自己的真实配置。
一、准备环境¶
创建 .env:
E2B_API_KEY=e2b_xxx
E2B_API_URL=https://api.cn-beijing.e2b.fc.aliyuncs.com
E2B_DOMAIN=cn-beijing.e2b.fc.aliyuncs.com
E2B SDK 会自动读取 E2B_API_URL 和 E2B_DOMAIN。为了让示例更明确,下文仍统一从环境变量或配置中读取。TypeScript SDK 使用 import 'dotenv/config' 自动加载 .env 文件。
二、通用辅助函数¶
后续示例可以复用下面的配置读取逻辑:
import os
from dotenv import load_dotenv
load_dotenv()
def require_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
raise RuntimeError(f"缺少环境变量: {name}")
return value
E2B_API_KEY = require_env("E2B_API_KEY")
E2B_CONN_OPTS = {
"api_url": require_env("E2B_API_URL"),
"domain": require_env("E2B_DOMAIN"),
}
生产代码中建议把 sandbox.kill() 放在 finally(Python)或 try/finally(TypeScript)中,确保异常时也能释放沙箱。
三、基础沙箱与命令执行¶
基础沙箱适合执行 Shell 命令、脚本、轻量调试任务。
from e2b import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
template="base",
api_key=E2B_API_KEY,
timeout=300,
**E2B_CONN_OPTS,
)
print(f"sandbox_id: {sandbox.sandbox_id}")
result = sandbox.commands.run("echo 'Hello, World!' && date")
print(result.stdout)
host = sandbox.get_host(3000)
print(f"port 3000 host: https://{host}")
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
});
try {
console.log(`sandboxId: ${sbx.sandboxId}`);
const result = await sbx.commands.run("echo 'Hello, World!' && date");
console.log(result.stdout);
const host = sbx.getHost(3000);
console.log(`port 3000 host: https://${host}`);
} finally {
await sbx.kill();
}
}
main();
常用参数:
| 参数 | Python | TypeScript | 说明 |
|---|---|---|---|
| 模板 | template="base" |
template: 'base'(创建选项内) |
沙箱模板名或模板 ID。未指定时使用默认模板。 |
| 存活时间 | timeout=300(秒) |
timeoutMs: 300_000(毫秒) |
不传时默认 300 秒。 |
| API Key | api_key=... |
apiKey: ... |
云沙箱 API Key。 |
| 连接参数 | api_url / domain |
SDK 自动读取 E2B_DOMAIN |
北京地域服务入口。 |
四、timeout 和续期行为¶
当前云沙箱的 timeout 语义已经与 E2B 对齐:
Template不提供 timeout 相关参数。模板用于定义镜像、CPU、内存、磁盘和预置环境。Sandbox.create(timeout=60, ...)表示创建出的沙箱初始存活时间为 60 秒。- 如果创建沙箱时不传
timeout,默认存活时间为 300 秒。 sandbox.set_timeout(...)/sandbox.setTimeout(...)用于续期,会把沙箱剩余存活时间重置为传入值。- 续期不是累加。例如沙箱还剩 120 秒时调用
sandbox.set_timeout(600),新的剩余存活时间是 600 秒,不是 720 秒。
如果任务可能运行超过默认时间,可以在创建时显式传入更大的 timeout,也可以在任务执行过程中按需续期:
from e2b import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
template="base",
api_key=E2B_API_KEY,
timeout=1800,
**E2B_CONN_OPTS,
)
# Python SDK 使用秒;这里把剩余存活时间重置为 1800 秒。
sandbox.set_timeout(1800)
result = sandbox.commands.run("python3 long_running_task.py", timeout=1700)
print(result.stdout)
finally:
if sandbox is not None:
sandbox.kill()
TypeScript 示例:
import { Sandbox } from 'e2b'
const sandbox = await Sandbox.create({
template: 'base',
timeoutMs: 1_800_000,
})
try {
// TypeScript SDK 使用毫秒;这里把剩余存活时间重置为 1800 秒。
await sandbox.setTimeout(1_800_000)
const result = await sandbox.commands.run('python3 long_running_task.py', {
timeoutMs: 1_700_000,
})
console.log(result.stdout)
} finally {
await sandbox.kill()
}
Warning
timeout / set_timeout / setTimeout 控制的是沙箱生命周期,不是业务重试机制。长任务仍应为命令执行设置合理超时,并确保最终释放沙箱。
五、代码解释器¶
代码解释器适合运行 Python 代码片段,并在同一个沙箱上下文中保留变量状态。
from e2b_code_interpreter import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
template="code-interpreter-v1",
api_key=E2B_API_KEY,
timeout=300,
**E2B_CONN_OPTS,
)
execution = sandbox.run_code("x = 1 + 2\nx")
print(execution.results[0].text)
execution = sandbox.run_code("print(f'x is {x}')")
print(execution.logs.stdout)
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from '@e2b/code-interpreter';
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
});
try {
const execution = await sbx.runCode('x = 1 + 2; x');
console.log(execution.results[0].text);
const execution2 = await sbx.runCode("print(f'x is {x}')");
console.log(execution2.logs.stdout);
} finally {
await sbx.kill();
}
}
main();
适合场景:
- AI Agent 生成 Python 代码后执行。
- 数据处理、计算、绘图前置计算。
- 需要多轮执行并复用变量状态的交互式任务。
六、文件系统操作¶
沙箱提供文件读写、列目录、创建目录、移动和删除等能力。
import json
from e2b import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
**E2B_CONN_OPTS,
)
sandbox.files.write("/tmp/hello.txt", "Hello, E2B!")
print(sandbox.files.read("/tmp/hello.txt"))
sandbox.files.write(
"/tmp/metadata.json",
json.dumps({"sandbox_id": sandbox.sandbox_id}, indent=2),
)
metadata = json.loads(sandbox.files.read("/tmp/metadata.json"))
print(metadata["sandbox_id"])
sandbox.files.make_dir("/tmp/work/subdir")
sandbox.files.write("/tmp/work/subdir/file.txt", "nested content")
print([item.name for item in sandbox.files.list("/tmp/work/subdir")])
sandbox.files.rename("/tmp/hello.txt", "/tmp/hello-renamed.txt")
sandbox.files.remove("/tmp/hello-renamed.txt")
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
});
try {
// 写入和读取文本文件
await sbx.files.write('/tmp/hello.txt', 'Hello, E2B!');
console.log(await sbx.files.read('/tmp/hello.txt'));
// 写入和读取 JSON 文件
await sbx.files.write('/tmp/metadata.json', JSON.stringify(
{ sandboxId: sbx.sandboxId }, null, 2));
const metadata = JSON.parse(await sbx.files.read('/tmp/metadata.json'));
console.log(metadata.sandboxId);
// 创建目录和嵌套文件
await sbx.files.makeDir('/tmp/work/subdir');
await sbx.files.write('/tmp/work/subdir/file.txt', 'nested content');
const files = await sbx.files.list('/tmp/work/subdir');
console.log(files.map(f => f.name));
// 重命名和删除
await sbx.files.rename('/tmp/hello.txt', '/tmp/hello-renamed.txt');
await sbx.files.remove('/tmp/hello-renamed.txt');
} finally {
await sbx.kill();
}
}
main();
建议:
- 临时文件优先放在
/tmp。 - 需要跨沙箱持久化的数据,应使用 OSS、NAS 等外部存储。
- 大文件传输建议结合上传/下载 URL 或对象存储,避免把大文件塞进控制面请求。
七、传入自定义环境变量¶
创建沙箱时可以通过 envs 注入业务环境变量。
from e2b import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
template="base",
api_key=E2B_API_KEY,
timeout=300,
envs={
"APP_MODE": "sandbox",
"TASK_ID": "task-001",
},
**E2B_CONN_OPTS,
)
result = sandbox.commands.run("echo $APP_MODE && echo $TASK_ID")
print(result.stdout)
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
async function main() {
const sbx = await Sandbox.create({
template: 'base',
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
envs: {
APP_MODE: 'sandbox',
TASK_ID: 'task-001',
},
});
try {
const result = await sbx.commands.run('echo $APP_MODE && echo $TASK_ID');
console.log(result.stdout);
} finally {
await sbx.kill();
}
}
main();
不要通过 envs 传递长期密钥。生产环境建议使用短期凭证、RAM Role 或专门的密钥注入机制。
八、Git 操作¶
沙箱可以克隆仓库、查看状态、提交变更、创建分支。适合代码分析、自动修复、构建验证等场景。
from e2b import Sandbox
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
**E2B_CONN_OPTS,
)
repo_url = "https://gitee.com/aliyunfc/Hello-World.git"
workdir = "/tmp/git-repo"
sandbox.git.clone(repo_url, workdir, depth=1)
status = sandbox.git.status(workdir)
print(status.current_branch, status.is_clean)
sandbox.git.configure_user("Sandbox Bot", "sandbox@example.com", path=workdir)
sandbox.files.write(f"{workdir}/sandbox-note.txt", "created in sandbox\n")
sandbox.git.add(workdir)
sandbox.git.commit(workdir, "Add sandbox note")
sandbox.git.create_branch(workdir, "feature/sandbox-test")
sandbox.git.checkout_branch(workdir, "feature/sandbox-test")
print(sandbox.git.status(workdir).current_branch)
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
});
try {
const repoUrl = 'https://gitee.com/aliyunfc/Hello-World.git';
const workdir = '/tmp/git-repo';
await sbx.git.clone(repoUrl, { path: workdir, depth: 1 });
const status = await sbx.git.status(workdir);
console.log(status.currentBranch, status.isClean);
await sbx.git.configureUser('Sandbox Bot', 'sandbox@example.com', { cwd: workdir });
await sbx.files.write(`${workdir}/sandbox-note.txt`, 'created in sandbox\n');
await sbx.git.add(workdir);
await sbx.git.commit(workdir, 'Add sandbox note');
await sbx.git.createBranch(workdir, 'feature/sandbox-test');
await sbx.git.checkoutBranch(workdir, 'feature/sandbox-test');
const branchStatus = await sbx.git.status(workdir);
console.log(branchStatus.currentBranch);
} finally {
await sbx.kill();
}
}
main();
如果要访问私有仓库,建议使用短期 Token,并注意不要把 Token 写入 Git 历史或日志。
九、动态端口访问¶
沙箱内启动 HTTP 服务后,可以通过 get_host(port) / getHost(port) 获取外部访问地址。
import time
from e2b import Sandbox
HTTP_PORT = 8080
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
allow_internet_access=True,
**E2B_CONN_OPTS,
)
sandbox.files.write(
"/tmp/www/index.html",
"<html><body><h1>Hello from sandbox!</h1></body></html>",
)
process = sandbox.commands.run(
f"python3 -m http.server {HTTP_PORT}",
cwd="/tmp/www",
background=True,
)
print(f"http server pid: {process.pid}")
time.sleep(2)
host = sandbox.get_host(HTTP_PORT)
print(f"external url: https://{host}")
result = sandbox.commands.run(f"curl -s http://localhost:{HTTP_PORT}/index.html")
print(result.stdout)
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
const HTTP_PORT = 8080;
function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
allowInternetAccess: true,
});
try {
await sbx.files.write(
'/tmp/www/index.html',
'<html><body><h1>Hello from sandbox!</h1></body></html>',
);
const proc = await sbx.commands.run(
`python3 -m http.server ${HTTP_PORT}`,
{ cwd: '/tmp/www', background: true },
);
console.log(`http server pid: ${proc.pid}`);
await sleep(2000);
const host = sbx.getHost(HTTP_PORT);
console.log(`external url: https://${host}`);
const result = await sbx.commands.run(
`curl -s http://localhost:${HTTP_PORT}/index.html`,
);
console.log(result.stdout);
} finally {
await sbx.kill();
}
}
main();
适合场景:
- 临时预览 Web 页面。
- 暴露沙箱内调试服务。
- 让外部工具通过 HTTPS 访问沙箱内 HTTP 服务。
十、列出模板¶
除了 CLI 的 e2b template list,也可以直接调用控制面 API 获取模板列表。
import requests
api_url = require_env("E2B_API_URL")
api_key = require_env("E2B_API_KEY")
response = requests.get(
f"{api_url}/templates",
headers={
"X-API-Key": api_key,
"Accept": "application/json",
},
timeout=30,
)
response.raise_for_status()
for template in response.json():
names = template.get("names") or template.get("aliases") or []
print({
"name": ", ".join(names) if names else "N/A",
"templateID": template.get("templateID"),
"buildStatus": template.get("buildStatus"),
"cpuCount": template.get("cpuCount"),
"memoryMB": template.get("memoryMB"),
})
import 'dotenv/config';
const E2B_API_KEY = process.env.E2B_API_KEY!;
const E2B_DOMAIN = process.env.E2B_DOMAIN!;
const E2B_API_URL = `https://api.${E2B_DOMAIN}`;
async function main() {
const response = await fetch(`${E2B_API_URL}/templates`, {
headers: {
'X-API-Key': E2B_API_KEY,
'Accept': 'application/json',
},
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
const templates = await response.json() as any[];
for (const template of templates) {
const names = template.names ?? template.aliases ?? [];
console.log({
name: names.length > 0 ? names.join(', ') : 'N/A',
templateID: template.templateID,
buildStatus: template.buildStatus,
cpuCount: template.cpuCount,
memoryMB: template.memoryMB,
});
}
}
main();
这个方式适合做控制台、巡检脚本或 CI 校验。
十一、VPC 网络配置¶
如果沙箱需要访问 VPC 内资源,可以在 metadata 中传入 VPC 配置。
import json
from e2b import Sandbox
vpc_config = {
"vpcId": "vpc-xxxxxxxx",
"securityGroupId": "sg-xxxxxxxx",
"vSwitchIds": ["vsw-xxxxxxxx"],
}
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
metadata={
"fc.sandbox.network.vpc": json.dumps(vpc_config),
},
**E2B_CONN_OPTS,
)
result = sandbox.commands.run("ip route && echo 'VPC config applied'")
print(result.stdout)
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
const vpcConfig = {
vpcId: 'vpc-xxxxxxxx',
securityGroupId: 'sg-xxxxxxxx',
vSwitchIds: ['vsw-xxxxxxxx'],
};
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
metadata: {
'fc.sandbox.network.vpc': JSON.stringify(vpcConfig),
},
});
try {
const result = await sbx.commands.run("ip route && echo 'VPC config applied'");
console.log(result.stdout);
} finally {
await sbx.kill();
}
}
main();
注意事项:
- VPC、交换机、安全组应位于沙箱服务支持的地域。
- 安全组需要允许沙箱访问目标服务端口。
- 如果结合 NAS,一般必须同时配置 VPC。
十二、挂载 OSS¶
OSS 挂载适合把对象存储作为沙箱内的工作目录或结果输出目录。
import json
from datetime import datetime
from e2b import Sandbox
mount_dir = "/mnt/oss"
oss_config = {
"mountPoints": [
{
"bucketName": "your-bucket-name",
"mountDir": mount_dir,
"bucketPath": "/",
"endpoint": "http://oss-cn-beijing-internal.aliyuncs.com",
"readOnly": False,
}
]
}
role_arn = "acs:ram::<account-id>:role/<role-name>"
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
metadata={
"fc.sandbox.storage.oss": json.dumps(oss_config),
"fc.sandbox.auth.role": role_arn,
},
**E2B_CONN_OPTS,
)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
path = f"{mount_dir}/e2b-test-{timestamp}.txt"
sandbox.files.write(path, f"Hello from OSS sandbox at {timestamp}\n")
print(sandbox.files.read(path))
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
const mountDir = '/mnt/oss';
const ossConfig = {
mountPoints: [
{
bucketName: 'your-bucket-name',
mountDir,
bucketPath: '/',
endpoint: 'http://oss-cn-beijing-internal.aliyuncs.com',
readOnly: false,
},
],
};
const roleArn = 'acs:ram::<account-id>:role/<role-name>';
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
metadata: {
'fc.sandbox.storage.oss': JSON.stringify(ossConfig),
'fc.sandbox.auth.role': roleArn,
},
});
try {
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 15);
const path = `${mountDir}/e2b-test-${timestamp}.txt`;
await sbx.files.write(path, `Hello from OSS sandbox at ${timestamp}\n`);
console.log(await sbx.files.read(path));
} finally {
await sbx.kill();
}
}
main();
注意事项:
role_arn需要具备对应 Bucket 的读写权限。- 内网 endpoint 需要与沙箱地域匹配。
- 如果只读访问,把
readOnly设置为True/true。
十三、挂载 NAS¶
NAS 挂载适合需要 POSIX 文件语义、目录共享或大规模文件读写的场景。NAS 通常需要和 VPC 配合使用。
import json
from datetime import datetime
from e2b import Sandbox
nas_mount_dir = "/mnt/nas"
nas_config = {
"mountPoints": [
{
"serverAddr": "<nas-mount-target>:/",
"mountDir": nas_mount_dir,
}
]
}
vpc_config = {
"vpcId": "vpc-xxxxxxxx",
"securityGroupId": "sg-xxxxxxxx",
"vSwitchIds": ["vsw-xxxxxxxx"],
}
sandbox = None
try:
sandbox = Sandbox.create(
api_key=E2B_API_KEY,
timeout=300,
metadata={
"fc.sandbox.storage.nas": json.dumps(nas_config),
"fc.sandbox.network.vpc": json.dumps(vpc_config),
},
**E2B_CONN_OPTS,
)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
test_dir = f"{nas_mount_dir}/e2b-test-{timestamp}"
sandbox.commands.run(f"sudo mkdir -p {test_dir}")
sandbox.commands.run(f"sudo chown user:user {test_dir}")
path = f"{test_dir}/hello.txt"
sandbox.files.write(path, "Hello from NAS sandbox\n")
print(sandbox.files.read(path))
finally:
if sandbox is not None:
sandbox.kill()
import 'dotenv/config';
import { Sandbox } from 'e2b';
const nasMountDir = '/mnt/nas';
const nasConfig = {
mountPoints: [
{
serverAddr: '<nas-mount-target>:/',
mountDir: nasMountDir,
},
],
};
const vpcConfig = {
vpcId: 'vpc-xxxxxxxx',
securityGroupId: 'sg-xxxxxxxx',
vSwitchIds: ['vsw-xxxxxxxx'],
};
async function main() {
const sbx = await Sandbox.create({
apiKey: process.env.E2B_API_KEY,
timeoutMs: 300_000,
metadata: {
'fc.sandbox.storage.nas': JSON.stringify(nasConfig),
'fc.sandbox.network.vpc': JSON.stringify(vpcConfig),
},
});
try {
const timestamp = new Date().toISOString().replace(/[-:T]/g, '').slice(0, 15);
const testDir = `${nasMountDir}/e2b-test-${timestamp}`;
await sbx.commands.run(`sudo mkdir -p ${testDir}`);
await sbx.commands.run(`sudo chown user:user ${testDir}`);
const path = `${testDir}/hello.txt`;
await sbx.files.write(path, 'Hello from NAS sandbox\n');
console.log(await sbx.files.read(path));
} finally {
await sbx.kill();
}
}
main();
注意事项:
- NAS 挂载点、VPC、交换机、安全组需要在同一网络链路内可达。
- 安全组和 NAS 权限组需要放通 NFS 访问。
- 生产环境建议把挂载目录和业务临时目录分开,避免误删共享数据。
十四、浏览器自动化¶
沙箱支持运行浏览器自动化任务。通过在沙箱内启动内置浏览器服务,暴露 CDP(Chrome DevTools Protocol)端点,外部工具(如 Playwright)可以通过 WebSocket 连接远端浏览器进行自动化操作。
Note
浏览器自动化需要使用预装了浏览器和 browsertool 的自定义镜像。以下示例会先从镜像构建模板,再创建沙箱启动浏览器服务。
import 'dotenv/config';
import { chromium } from 'playwright';
import { Sandbox, Template } from 'e2b';
const E2B_API_KEY = process.env.E2B_API_KEY!;
const image = 'your-registry.cn-beijing.cr.aliyuncs.com/namespace/browser-image:tag';
const templateName = `browser-demo-${Math.floor(Date.now() / 1000)}`;
const BROWSERTOOL_PORT = 3000;
const PC_CONFIG = '/etc/sandbox/config/process-compose.browsertool.yaml';
function sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function startBrowsertool(sbx: Sandbox) {
await sbx.commands.run(
'install -d -m 1777 /tmp/.X11-unix && rm -f /tmp/.X1-lock && mkdir -p /run/user/1000/dconf',
{ user: 'root' },
);
const chromePathResult = await sbx.commands.run('cat /etc/browsertool/chrome-path', { user: 'root' });
const chromePath = chromePathResult.stdout.trim();
await sbx.commands.run(
`process-compose up -f ${PC_CONFIG} --tui=false --no-server > /tmp/browsertool-pc.log 2>&1`,
{
envs: { SXBT_BROWSER_CHROMIUM_PATH: chromePath },
background: true,
user: 'root',
},
);
const deadline = Date.now() + 60000;
while (Date.now() < deadline) {
const r = await sbx.commands.run(
`curl -sS -m 2 -o /dev/null -w '%{http_code}' http://localhost:${BROWSERTOOL_PORT}/health || true`,
{ user: 'root' },
);
if (r.stdout.trim() === '200') return;
await sleep(2000);
}
throw new Error('browsertool 在 60s 内未就绪');
}
async function main() {
// 1. 构建模板
const registryTemplate = Template().fromImage(image);
const buildInfo = await Template.build(registryTemplate, templateName, {
apiKey: E2B_API_KEY,
cpuCount: 2,
memoryMB: 2048,
});
// 2. 创建沙箱
const sbx = await Sandbox.create({
template: buildInfo.name,
apiKey: E2B_API_KEY,
timeoutMs: 600_000,
allowInternetAccess: true,
});
try {
// 3. 启动浏览器服务
await startBrowsertool(sbx);
// 4. 获取 CDP WebSocket 端点
const host = sbx.getHost(BROWSERTOOL_PORT);
const cdpWsUrl = `wss://${host}/ws/automation`;
console.log(`CDP endpoint: ${cdpWsUrl}`);
// 5. 通过 Playwright 连接远端浏览器
const headers: Record<string, string> = {};
const token = sbx.trafficAccessToken;
if (token) headers['X-Access-Token'] = token;
const browser = await chromium.connectOverCDP(cdpWsUrl, { headers });
const context = browser.contexts().length > 0 ? browser.contexts()[0] : await browser.newContext();
const page = await context.newPage();
try {
await page.goto('https://example.com', { waitUntil: 'domcontentloaded', timeout: 30000 });
console.log(`page title: ${await page.title()}`);
} finally {
await page.close();
await browser.close();
}
} finally {
await sbx.kill();
}
}
main();
关键步骤:
- 构建模板:使用预装浏览器的镜像构建模板。
- 创建沙箱:设置较长的
timeoutMs和allowInternetAccess: true。 - 启动浏览器服务:通过
process-compose启动 browsertool,等待/health就绪。 - 获取 CDP 端点:通过
getHost(port)获取外部可达的 WebSocket 地址。 - 连接浏览器:使用 Playwright 的
connectOverCDP连接远端浏览器。
注意事项:
- 公网网关要求通过
X-Access-Token头认证 WebSocket 连接,使用sbx.trafficAccessToken获取。 - 浏览器镜像体积较大,首次构建模板可能需要几分钟。
- 建议设置较长的沙箱超时时间(如 600 秒),浏览器自动化任务通常耗时较长。
十五、能力兼容概览¶
当前服务对 E2B Python SDK 和 TypeScript SDK 的核心能力兼容情况如下:
SDK 能力¶
| 能力 | 状态 | 说明 |
|---|---|---|
| Sandbox 创建、连接、列表、销毁 | 支持 | 支持 template / timeout / envs / metadata |
sandbox.set_timeout() / sandbox.setTimeout() |
支持 | 实例方法和静态方法均支持 |
sandbox.pause() / sandbox.resume() |
支持 | 需要特定地域支持 |
sandbox.getHost(port) / sandbox.downloadUrl / sandbox.uploadUrl |
支持 | 客户端生成 URL |
| Commands 运行命令、后台进程、PTY | 支持 | 包括 run / list / connect / sendStdin / kill |
| Filesystem 读写、列目录、创建目录、移动、删除、监听 | 支持 | 完整文件系统操作 |
| Code Interpreter Python / JavaScript 执行和上下文 | 支持 | 含 runCode / createContext / 上下文生命周期管理 |
| Git 操作 | 支持 | clone / status / add / commit / branch 等 |
| Template 创建、构建、列表、标签和别名 | 支持 | v1/v2/v3 全版本 |
CLI sandbox create/list/kill、template list |
支持 | E2B CLI 核心命令 |
| Metrics、Logs | 部分 Stub | 兼容调用但不建议依赖完整语义,控制台视角完全兼容 |
| Snapshots | 暂不支持 | 返回 501 Not Implemented |
| Volume API、API Key 管理、Access Token 管理、Team API | 暂不支持 | — |
API 兼容汇总¶
| 维度 | 支持情况 |
|---|---|
| 控制面 API | 24/44 完整实现,6 个 Stub,14 个不支持 |
| 数据面 API | 21/21 全部完整实现(进程管理 7 + 文件系统 7 + Code Interpreter 5 + 健康检查 2) |
| 认证方式 | X-API-Key 和 Authorization: Bearer 均支持 |
FC metadata 扩展能力¶
以下能力通过 metadata 参数传入,是函数计算云沙箱的扩展能力,不属于 E2B 官方 SDK:
| metadata key | 说明 |
|---|---|
fc.sandbox.network.vpc |
VPC 网络配置 |
fc.sandbox.storage.oss |
OSS 对象存储挂载 |
fc.sandbox.storage.nas |
NAS 文件存储挂载 |
fc.sandbox.auth.role |
RAM Role ARN,用于 OSS 等服务的权限 |
如果业务依赖不支持的 E2B 官方能力,建议优先使用 FC metadata 扩展能力、OSS、NAS 或应用侧控制面逻辑替代。