跳转到内容
本站为社区维护的非官方中文翻译,与 Cloudflare, Inc. 无关联。本站不提供账户登录,请勿在任何非官方站点输入您的 Cloudflare 账户信息。官方文档:developers.cloudflare.com

终端

最后更新 查看 MarkdownAgent 设置

通过 WebSocket 将基于浏览器的终端 UI 连接到沙箱 shell。服务端的 terminal() 方法将 WebSocket 连接代理到容器,客户端的 SandboxAddon 与 xterm.js 集成以进行终端渲染。

服务端方法

terminal()

代理 WebSocket 升级请求以创建终端连接。

const response = await sandbox.terminal(request: Request, options?: PtyOptions): Promise<Response>

参数:

  • request - 来自浏览器的 WebSocket 升级请求(必须包含 Upgrade: websocket 标头)
  • options(可选):
    • cols - 终端宽度(列数,默认:80)
    • rows - 终端高度(行数,默认:24)

返回值:Promise<Response> — WebSocket 升级响应

// In your Worker's fetch handler
return await sandbox.terminal(request, { cols: 120, rows: 30 });
// In your Worker's fetch handler
return await sandbox.terminal(request, { cols: 120, rows: 30 });

适用于默认会话和明确创建的会话:

// Default session
return await sandbox.terminal(request);

// Specific session
const session = await sandbox.getSession("dev");
return await session.terminal(request);
// Default session
return await sandbox.terminal(request);

// Specific session
const session = await sandbox.getSession('dev');
return await session.terminal(request);

客户端 addon

@cloudflare/sandbox/xterm 模块为 xterm.js 提供 SandboxAddon,负责处理 WebSocket 连接、重连以及终端尺寸调整转发。

SandboxAddon

import { SandboxAddon } from '@cloudflare/sandbox/xterm';

const addon = new SandboxAddon(options: SandboxAddonOptions);

选项:

  • getWebSocketUrl(params) - 为每次连接尝试构建 WebSocket URL。接收:
    • sandboxId - 目标沙箱 ID
    • sessionId(可选)- 目标会话 ID
    • origin - 从 window.location 派生的 WebSocket origin(例如 wss://example.com)
  • reconnect - 启用带指数退避的自动重连(默认:true)
  • onStateChange(state, error?) - 连接状态变更的回调
import { Terminal } from "@xterm/xterm";
import { SandboxAddon } from "@cloudflare/sandbox/xterm";

const terminal = new Terminal({ cursorBlink: true });
terminal.open(document.getElementById("terminal"));

const addon = new SandboxAddon({
	getWebSocketUrl: ({ sandboxId, sessionId, origin }) => {
		const params = new URLSearchParams({ id: sandboxId });
		if (sessionId) params.set("session", sessionId);
		return `${origin}/ws/terminal?${params}`;
	},
	onStateChange: (state, error) => {
		console.log(`Terminal ${state}`, error);
	},
});

terminal.loadAddon(addon);
addon.connect({ sandboxId: "my-sandbox" });
import { Terminal } from '@xterm/xterm';
import { SandboxAddon } from '@cloudflare/sandbox/xterm';

const terminal = new Terminal({ cursorBlink: true });
terminal.open(document.getElementById('terminal'));

const addon = new SandboxAddon({
  getWebSocketUrl: ({ sandboxId, sessionId, origin }) => {
    const params = new URLSearchParams({ id: sandboxId });
    if (sessionId) params.set('session', sessionId);
    return `${origin}/ws/terminal?${params}`;
  },
  onStateChange: (state, error) => {
    console.log(`Terminal ${state}`, error);
  }
});

terminal.loadAddon(addon);
addon.connect({ sandboxId: 'my-sandbox' });

connect()

建立与沙箱终端的连接。

addon.connect(target: ConnectionTarget): void

参数:

  • target:
    • sandboxId - 要连接的沙箱
    • sessionId(可选)- 沙箱内的会话

使用新目标调用 connect() 会断开当前目标并连接到新目标。在已连接时使用相同目标调用则无操作。

disconnect()

关闭连接并停止任何重连尝试。

addon.disconnect(): void

属性

属性 类型 描述
state 'disconnected' | 'connecting' | 'connected' 当前连接状态
sandboxId string | undefined 当前沙箱 ID
sessionId string | undefined 当前会话 ID

WebSocket 协议

SandboxAddon 会自动处理 WebSocket 协议。以下细节适用于不使用该 addon 构建自定义终端客户端的情况。完整示例参见不使用 xterm.js 进行连接。

连接生命周期

  1. 客户端向你的 Worker 端点打开 WebSocket。将 binaryType 设为 arraybuffer。
  2. 服务端将先前连接的任何缓冲输出 以二进制帧回放。这可能在 ready 消息之前到达。
  3. 服务端发送 ready 状态消息 — 终端现在接受输入。
  4. 二进制帧双向流动:客户端发送 UTF-8 编码的按键,服务端发送终端输出(包括 ANSI 转义序列)。
  5. 如果客户端断开连接,PTY 保持存活。重新连接到同一会话会回放缓冲输出,使终端看起来未改变。

控制消息(客户端到服务端)

发送 JSON 文本帧以控制终端。

Resize — 更新终端尺寸(cols 与 rows 都必须为正数):

{ "type": "resize", "cols": 120, "rows": 30 }

状态消息(服务端到客户端)

服务端为生命周期事件发送 JSON 文本帧。

Ready — PTY 已初始化。缓冲输出(如有)已发送:

{ "type": "ready" }

Exit — shell 进程已终止:

{ "type": "exit", "code": 0, "signal": "SIGTERM" }

Error — 发生错误(例如无效控制消息或会话未找到):

{ "type": "error", "message": "Session not found" }

类型

interface PtyOptions {
	cols?: number;
	rows?: number;
}

type ConnectionState = "disconnected" | "connecting" | "connected";

interface ConnectionTarget {
	sandboxId: string;
	sessionId?: string;
}

interface SandboxAddonOptions {
	getWebSocketUrl: (params: {
		sandboxId: string;
		sessionId?: string;
		origin: string;
	}) => string;
	reconnect?: boolean;
	onStateChange?: (state: ConnectionState, error?: Error) => void;
}

相关资源

这篇文档对您有帮助吗?