onesvm-browser-server/README.md
chii 9b689b2476 feat: 落地节点指纹与 Cookie 罐,并按现网能力更新消费/接手文档
公开页抓取改为 Chrome 136 自洽身份 + 每节点 SQLite 养罐,Trafilatura 走 curl_cffi;MCP/README/接手说明与 09-02 现网复测对齐,避免消费方继续抄过期的站点三分表。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 17:04:25 +08:00

127 lines
7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# onesvm-browser-server
面向智能体的**自构建联网搜索服务**:消费者拿一把 `X-Service-Token`,用 MCP(主)或 HTTP(兜底)调用 `search` / `read`。国内直连,国外走自有代理池,query **不经过** Tavily / Jina 等境外 SaaS。
现网入口:`http://192.168.1.51:8640`(MCP `POST /mcp`,HTTP `POST /v1/search` `/v1/read`)。
| 你是谁 | 先读 |
|---|---|
| 消费方(Vlepontas / EAI) | [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) → [`docs/integration-vlepontas-20260901.md`](docs/integration-vlepontas-20260901.md) |
| 接手开发 | [`docs/dev-handoff-20260902.md`](docs/dev-handoff-20260902.md)(本文下面是设计与选型摘要) |
| 改架构 / 拍板 | [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md)(决策权威)→ [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md)(机制权威) |
---
## 1. 要解决什么问题
智能体需要「上网查公开页」。买境外 SaaS 会把 query 送出境,且按次计费;自建浏览器集群又容易把整机内存和出口 IP 打爆。本仓的约束是:
- **境内闭环**:搜索与精读默认不经境外托管 API。
- **内存纪律**:常驻业务峰 ≤1GB(L2);60 = 队列深度,不是 60 个浏览器。
- **零 Redis**:SQLite WAL 单写者排队。
- **诚实能力**:公开网页大约九成;登录墙 / 强 WAF / Google 搜索不承诺。住宅 IP 是另一条带成本声明的通道,本服务不做。
人交「事件怎么活、怎么死、多快死」;实现按 [`onesvm-dev-md/base/engineering-standards.md`](../onesvm-dev-md/base/engineering-standards.md) 事件表,缺格不补默认值开工。
---
## 2. 设计科学(为什么长这样)
### 2.1 统一出口,双形态同一内核
所有消费者注册主体、拿可吊销 key。MCP 与 HTTP 共用 **Auth → Policy → Queue → Engine**。错误码两面对齐。静态服务密钥只走 `X-Service-Token`,禁止塞进 `Authorization: Bearer`。
### 2.2 分层内核,而不是「一个大浏览器」
流量大约 90% 是搜索 + 纯 HTTP 精读,不该进 Chromium。
| 层 | 适配器 | 何时用 |
|---|---|---|
| A 无浏览器 | SearXNG-CN / SearXNG-Global / Trafilatura | 搜索发现、静态正文 |
| B 轻渲染 | Lightpanda | HTTP 抽空、需要一点 JS |
| C 保真 | chrome-headless-shell(按需槽,默认 0 副本) | 轻核不够时 |
| 预留 | Camoufox / 有头档 | 强对抗 + 住宅 IP,不在 1GB 预算内 |
降级链:C 满 → B → A → `blocked`/`upstream`。Cloudflare / WAF / 验证页**不拿渲染空转**,直接 `blocked`。
### 2.3 出口与身份分开记账
- **出口**:国内域直连;境外经 ProxyManager + mihomo vless 热池。决定「Google 过不过」的是 IP 信誉,不是 UA 字符串。
- **身份(P0/P1,2026-09-02 落地)**:每生产节点 8 套 Chrome 136 模版(与 Trafilatura `curl_cffi` `impersonate=chrome136` 自洽);一等 Cookie 养在本节点 SQLite。罐按 **模版 × http|cdp × 出口 × eTLD+1** 隔离,节点内共享、不按消费者拆。登录态 Cookie 名直接丢弃。403/验证页整域丢罐。Cookie **不进 MCP、不进 jobs.payload**。
Go 侧 `httpx` 仍是 Go TLS,UA 写诚实的 `onesvm-browser-server-httpx/1.0`,禁止再伪装 Chrome(TLS/UA 必须自洽)。
### 2.4 合规双向保险
请求侧在网关:SSRF、仅 80/443、域名策略、普通 key 遵守 robots。响应侧在 worker 模版层:体积/类型白名单、词表、PII 脱敏、注入包裹。命中即 `denied` 并审计,不假装成功。
---
## 3. 选用方案(实测后入选,不是目录堆砌)
2026-09-01 本机 Docker 评分(内存 30% / 质量 25% / 成功率 20% / 延迟 15% / 运维 10%)。全文:[`docs/decision-candidates-20260901.md`](docs/decision-candidates-20260901.md)。
| 方案 | 分 | 角色 | 为什么留 |
|---|---:|---|---|
| Trafilatura-HTTP | 96.8 | 默认精读 | 60/60、p50 ~60ms、正文干净;现网已加 curl_cffi |
| Lightpanda | 91.0 | 默认 JS | idle 3.6MB;CF/Amazon 仍过不了 |
| chrome-headless-shell | 85.5 | 保真按需 | 单槽 FIFO 零拒绝;重页 ~400MB |
| SearXNG-CN | 71.5 | 国内搜索 | 政策词准;突发时百度/搜狗 CAPTCHA,靠排队钳 4–8 |
| SearXNG-Global | 62.0 | 国外搜索 | 实例稳,但数据中心 IP 下 **仅 Bing**;产品不承诺多源 |
**明确排除**:playwright-distributed(Redis)、Browserless(4GB 档)、Jina 云(query 出境)、Firecrawl 自托管(与 shell+模版层重叠且更重)。
**用户已拍板**:D1 先 L0→L2(≤1GB);D2 接受 Bing-only 起步;D5 不做 Camoufox;Amazon 本站非本服务刚需。
现网能力以 [`docs/mcp-usage-20260901.md`](docs/mcp-usage-20260901.md) §4 为准(2026-09-02 mgr1 复测),不要把 09-01 bench 的「BBC 稳取 / Amazon 一律不行」抄进消费方文档。
---
## 4. 仓库地图
```
server/ Go 单二进制,-role=gateway|scheduler|proxymanager
cmd/browser-server/ 入口
internal/contract/ 信封与 Job(Session 字段 json:"-")
internal/gateway/ MCP + /v1 + Auth + 策略预检
internal/scheduler/ 队列、路由、模版层整合器、junk 过滤、Cookie 绑定
internal/dock/ 五适配器(SearXNG×2、Trafilatura、Lightpanda、shell)
internal/fingerprint/ 每节点 Chrome 136 模版
internal/session/ Cookie 罐(Sanitize / TTL / reap)
internal/store/ SQLite(jobs、keys、fp_*、session_cookies)
internal/proxymanager/ 订阅 / 探活 / 域名路由
internal/policy/ SSRF / robots / 域名
internal/safetyscan/ 响应侧词表与包裹
stacks/ Swarm stack + SearXNG 配置 + Trafilatura 镜像
scripts/ smoke-local.sh、deploy-mgr1.sh(默认 dry-run)
bench/ 选型期实测(无密钥)
docs/ 决策 / 机制 / MCP / 接手
```
源文件硬上限 **600 行**(`make wc`)。禁止万能 `util` 包。
---
## 5. 本机怎么跑
```bash
make test # go test(合入前加 -race:cd server && go test -race ./...)
make vet
make smoke # compose + stub 引擎,12 步断言
make image # onesvm/browser-server:dev(默认 linux/amd64)
make image-trafilatura # onesvm/trafilatura-http:dev
```
生产节点通常拉不到 Docker Hub。镜像必须在可联网机器构建/拉取,再 `docker save | ssh … docker load`,stack 用 `--resolve-image never`。**同 tag 覆盖后必须 `docker service update --force`**,否则任务还跑旧层。
mgr1 部署属 🟡:只在用户明确「确认执行」后跑 `bash scripts/deploy-mgr1.sh --apply`。密钥在 gitignore 的 `deploy.env`,不入 git。
---
## 6. 文档索引
完整表见 [`docs/README.md`](docs/README.md)。冲突时:
1. [`docs/plan-final-20260901.md`](docs/plan-final-20260901.md) — 决策
2. [`docs/design-arch-20260901.md`](docs/design-arch-20260901.md) — 机制
3. 代码 — 现网行为(文档会过期,以代码与 §4 现网复测为准)