接入 Playwright Worker、会话 WebSocket 与全局浏览器面板(固定于 App Bar 下); 含验证码 stealth、设置项默认音与 URL 安全校验;附带 worker 部署与设计文档。 Co-authored-by: Cursor <cursoragent@cursor.com>
7.2 KiB
服务端远程浏览器(Playwright Chromium)— 设计说明
取代 iframe 渲染方案(2026-06-11-embedded-browser-design.md 中的页面加载方式)。
UI 状态(标签、收藏nav_links、窗口位置)仍走/api/browser/state,不变。
背景与目标
运维需要在 Nexus 浮动面板内完整浏览任意公网站点,不受 X-Frame-Options / CSP frame-ancestors 限制,且使用服务端独立浏览器内核,而非用户本机标签页内的 iframe。
用户确认(2026-06-11)
| 决策项 | 选择 |
|---|---|
| 可访问范围 | 任意公网 http / https |
| 内核 | Chromium(Playwright),不要求 Firefox |
| 交互 | 在 Nexus 面板内看画面 + 键鼠操作(非「新标签打开」为主) |
与 iframe 方案对比
| iframe(现状) | 服务端 Chromium(目标) | |
|---|---|---|
| 渲染位置 | 用户浏览器 | Nexus 服务器 |
| 站点嵌入限制 | 常被拒绝 | 无(顶层窗口) |
| SSRF 风险 | 无 | 有,必须缓解 |
| 资源 | 几乎无 | 每会话 ~200–500MB RAM |
| Cookie / 登录 | 用户本机 | 服务器浏览器 Profile |
方案概述
类比 RDP(guacd → WebSocket → 前端画布),但 Nexus 拥有浏览器进程与协议:
管理员浏览器 (Vue SPA)
│ JWT WebSocket + REST
▼
Nexus API (FastAPI) — 桥接,不跑 Chromium
│ Worker Key + 内网 HTTPS
▼
Browser Worker VPS — Playwright Chromium(headless + CDP screencast)
▼
公网目标站点
| 组件 | 职责 |
|---|---|
| Playwright Chromium | 运行在 Browser Worker;Nexus 桥接会话 |
| URL 安全网关 | 导航前 DNS 解析 + IP 段校验,阻断私网/元数据 SSRF |
/ws/browser/{session_id} |
推送 JPEG 帧;接收 navigate / 键鼠 / 滚动 |
POST/DELETE /api/browser/sessions |
创建、销毁会话 |
GlobalBrowserPanel |
<canvas> 替代 <iframe>;保留地址栏、标签、收藏、最小化 |
/api/browser/state |
不变 — tabs、visits、nav_links、rect |
刻意不做(首版)
- 不做 HTTP 反向代理(HTML 改写 / Cookie 注入)
- 不做浏览内容审计或页面录制落库
- 不做多管理员并发压测级扩展(单人运维,全局并发 ≤2)
- 不做本机 Cookie 与服务器 Profile 双向同步
WebSocket 协议(草案)
鉴权:与终端/RDP 一致,query ?token= = 常规 access JWT(sub = admin_id),且 session 归属该校验通过的管理员。
服务端 → 客户端
| type | 字段 | 说明 |
|---|---|---|
BROWSER_INIT |
session_id, viewport_w, viewport_h |
连接就绪 |
SCREENCAST_FRAME |
data_b64, metadata |
CDP screencast JPEG |
PAGE_INFO |
url, title |
导航完成或标题变化 |
ERROR |
message, code |
URL 拒绝、超时、Playwright 错误 |
PONG |
— | 心跳 |
客户端 → 服务端
| type | 字段 | 说明 |
|---|---|---|
NAVIGATE |
url |
经 SSRF 校验后 page.goto |
RELOAD / GO_BACK / GO_FORWARD |
— | 历史导航 |
MOUSE |
event, x, y, button |
move / down / up / wheel |
KEY |
event, key, code, text |
down / up / type |
VIEWPORT |
width, height |
面板尺寸变化 |
PING |
— | 心跳 |
坐标:x/y 为相对 viewport 的 CSS 像素,与 screencast 帧尺寸一致。
SSRF 防护(任意公网)
导航与每次 redirect 后 重新校验 最终 URL:
- 仅
http:/https:;拒绝凭据、javascript:、data:、file: - 解析 hostname →
getaddrinfo→ 所有解析 IP 必须不在阻断段:127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16169.254.0.0/16,0.0.0.0/8,100.64.0.0/10- IPv6:
::1,fc00::/7,fe80::/10
- 阻断常见 metadata 主机名(如
169.254.169.254、*metadata*字面) - 导航超时 30s;单页资源不限制由 Chromium 自身处理
- 失败时 WS 返回
ERROR,不静默降级
单人运维下 residual risk:DNS rebinding 需 TTL 短重查或 redirect 链逐跳校验;首版采用 redirect 监听 + 每跳校验。
会话与资源
| 策略 | 值 |
|---|---|
| 每管理员活跃会话 | 1 |
| 全局活跃会话 | ≤2 |
| 空闲超时 | 30 min 无 WS 活动 → 关闭 browser context |
| 视口默认 | 1280×720(可随面板 resize) |
| Screencast | CDP Page.startScreencast, JPEG quality ~80 |
进程模型:单例 Playwright Browser 进程 + 每会话独立 BrowserContext(隔离 Cookie)。
部署(选定:独立 Worker 服务器)
Playwright Chromium 不装入 Nexus 主站镜像,而在**单独 VPS(Browser Worker)**运行;Nexus 主站仅桥接 WebSocket。
管理员浏览器 → Nexus API(JWT)→ Browser Worker(Worker Key)→ 公网
| 组件 | 部署位置 |
|---|---|
browser-worker/ 服务 + Chromium |
Worker VPS(2C4G 起) |
/api/browser/sessions、/ws/browser/* 桥接 |
Nexus 主站 |
| MySQL UI 状态 | Nexus 主站(不变) |
Nexus 主站 .env
NEXUS_BROWSER_ENABLED=1
NEXUS_BROWSER_WORKER_URL=https://<worker-internal-or-vpn>:8443
NEXUS_BROWSER_WORKER_SECRET=<shared-secret>
NEXUS_BROWSER_MAX_SESSIONS=2
NEXUS_BROWSER_IDLE_TIMEOUT_SEC=1800
Worker 防火墙:8443 仅 Nexus 主站 IP;不对公网开放 Worker API。
降级:NEXUS_BROWSER_ENABLED=0 或 Worker 不可达 → POST /api/browser/sessions 503;前端提示「服务端浏览器未启用」。
— Worker 模式不修改主站镜像体积。Dockerfile.prod 增加 Chromium
前端变更
GlobalBrowserPanel.vue:<iframe>→<canvas>+useRemoteBrowserSession.ts- 保留:浮动/最小化/不可关闭/重启、标签、历史、收藏(nav_links 待做 UI)
- 移除或隐藏:「新标签打开」可保留作 导出 URL 辅助,非主路径
useGlobalBrowser.ts:navigate改为 WSNAVIGATE;frameKey不再需要
安全与隐私
- 页面内容经 JPEG 帧过 Nexus,不持久化截图
- 服务器 Chromium 内 Cookie 存于容器 ephemeral context(重启会话丢失)
- 仅
get_current_admin可创建/连接会话 - CUD:创建/销毁会话可选写 audit(首版 不做,与 RDP 无连接审计一致)
验收标准
- 打开
https://example.com等公网站,面板 canvas 有画面且可点击链接 - 曾 iframe 白屏的站点(如带
X-Frame-Options: DENY的站)可正常显示 - 访问
http://127.0.0.1/http://10.x/ metadata → 明确 ERROR,不发起请求 - 刷新页面后会话内 Cookie 保留;重启浏览器会话 Cookie 清空
- 标签、收藏、窗口位置仍持久化到
/api/browser/state NEXUS_BROWSER_ENABLED=0时有可读降级提示- Worker VPS 部署完成,防火墙仅 Nexus 主站可连
回滚
- 设
NEXUS_BROWSER_ENABLED=0→ 503,前端可回退 iframe 分支(保留 feature flag 一段过渡期) - 卸载 Playwright 依赖仅当确认不再使用