源码教程:从 HTTP 请求到命令执行
本系列以当前 deepseek-browser-use 工程为准,按功能解释全部 116 个注册命令,以及额外的 commands 批量入口。先阅读本章理解公共执行链,再按章节进入具体实现。文中的源码路径均相对于浏览器项目根目录;示例中的 ID、域名及资料均为占位信息。
1. 建立源码地图
| 文件或类 | 职责 |
|---|---|
playwright-server/src/main/java/nexus/io/ai/browser/handler/PlaywrightHandler.java | 接收 POST,解析 JSON,调用执行层,格式化响应并记录追踪 |
service/ActionService.java | 单条和批量执行的公共流程、安全重试、截图附加、异步作业 |
actions/registry/CommandTable.java | 注册命令名,读取参数,调用对应 Java 方法 |
service/PlaywrightService.java | 操作任务、Page、Frame、Locator 与浏览器上下文 |
service/BrowserInstance.java | 每个任务的当前页、DOM 快照、网络记录、弹窗等状态 |
dom/service/DomService.java | 注入 DOM 采集脚本,构造带 frame 信息的索引 |
handler/ResponseFormatter.java | 输出精简响应,保留业务结果 |
handler/CommandTraceLog.java | 记录命令追踪;规则脱敏不等于所有留档都脱敏 |
表中未写完整前缀的 Java 文件,均在 playwright-server/src/main/java/nexus/io/ai/browser/ 下。配置通过 EnvUtils.get 等框架配置入口读取;不要在扩展实现中直接读取系统环境变量。新增业务标识可用 nexus.io.tio.utils.snowflake.SnowflakeIdUtils.id() 生成。
2. 一条命令经过哪些层
POST /playwright/command
→ PlaywrightHandler.dispatch:方法与 JSON 校验
→ ActionService.execute:区分 commands 与单条命令
→ CommandTable:读取必填/可选参数,选定执行器
→ PlaywrightService:查找任务,定位对象,执行浏览器操作
→ ActionService:处理可安全重试的异常、附加截图
→ ResponseFormatter:按请求裁剪协议字段
→ CommandTraceLog:追踪记录
→ HttpResponse
请求形状保持一致,避免每个能力设计一个 Controller 地址:
{"id":"1001","method":"get_title","params":{}}
id 由 JSON 转为 Long,支持数字字符串;非法数字、空请求、非对象 JSON、缺失 method 都在入口返回失败。params 可以省略,由执行层处理。start 可省略 ID,其他方法是否依赖已有实例还要看该方法的实现,不能根据 Java 参数存在就推断必需浏览器页签。
3. 注册表如何连接参数与 Java 方法
以下是真实注册方式的简化展示:
put("get_element_attribute", (svc, id, args) ->
svc.getElementAttribute(id, reqInt(args, "index"), reqStr(args, "name")));
reqInt、reqStr 等负责必填参数;optStr 和 JSON 对象的可空 getter 保留“未传”状态,让服务方法决定默认值。不要把可选 Boolean 全部提前变成 false,例如截图、无头启动、停止策略各有自己的默认行为。
本系列各章末尾的“注册参数与入口”来自这张表:* 表示注册层要求该字段;“可选”不等于任何组合都有效,例如 index 与 selector 经常至少需要一个。方法内部仍会检查业务组合、范围和运行环境。
4. 返回值与错误不能只看一个字段
成功外层通常为 ok=true、code=1,业务内容在 data。失败原因在 msg,部分命令附有 errorCode、retryable 或诊断信息。不同方法的 data 结构不同,不应统一强转为某一种固定业务对象。
动作执行与业务成功分开:按钮被点击、DOM 变化、请求已发送,都不能替代“审核已提交”或“订单已支付”。观察代码会比较动作前后的 URL、页签、文本、表单状态及 DOM 指纹,并短暂等待异步变化。observationComplete=false 时,探针没有取得充分证据,不要依据 changed=false 重复提交。
对象释放异常可能由事件泵在操作后投递。ActionService 只对安全名单中的只读命令进行有限重试;点击、提交等动作不能自动重发。execute_js 只有在调用方确认纯读取并显式传 retryOnSpurious:true 时才允许这类重试。详见防重复提交。
5. 学习顺序与扩展方法
- 生命周期、导航和页签:先理解任务和共享浏览器。
- DOM、页面状态与元素读取:理解索引来自哪里。
- 点击、输入、键盘和鼠标:把索引转为实际交互。
- 等待与 JavaScript:处理异步页面。
- 上传、截图、PDF 与 OCR:处理文件和图像。
- Cookie、存储与设置:区分 Page 与 Context。
- 网络与控制台:将操作与请求结果关联。
- 对话框与人机协作:处理页面弹窗和人工步骤。
- 配方、批量、后台作业与维护:组合能力并管理运行状态。
增加命令时先确定它是否需要实例、是否可能改变页面、是否可以安全重试,再注册参数读取和服务方法。随后检查 PAGE_CHANGING、重试名单、响应精简和技能命令一致性测试;不能把所有新方法一律加入重试名单。
测试优先使用本地 HTML 和本地 HTTP 服务,不用真实商户申请验证点击。断言应检查页面状态、副作用次数、返回信息和失败分类,而不只是 ok=true。
