源码教程:Cookie、存储与页面设置
这一组命令最容易混淆作用域。任务的 Page 可以独立,但 BrowserContext 可能共享;修改上下文会影响多个任务。不能把所有 set 开头的命令都当作当前页设置。
1. Cookie 是 Context 级数据
| 命令 | 实现 |
|---|---|
get_cookies | 调用 context.cookies,可按 URL 过滤;将 Cookie 对象转为字段列表并返回 count |
set_cookie | 创建含 name、value 的 Cookie,按可选 url 设置作用域,再调用 addCookies |
clear_cookies | 调用 context.clearCookies,清除共享上下文 Cookie,不是只清当前域名 |
当前 set_cookie 命令没有暴露 domain/path 等完整 Cookie 构造参数。实际使用应提供有效 URL;不能因为 url 在注册层可选就认为缺少作用域的 Cookie 一定能添加成功。
{"id":"1001","method":"set_cookie","params":{"name":"demo_preference","value":"compact","url":"https://example.com"}}
不要在公开示例中使用真实登录 Cookie。读取 Cookie 的返回属于账号数据,不能因为是只读操作就随意写入教程。
2. localStorage 由当前页面 origin 决定
get_local_storage 在当前 Page 执行脚本:传 key 时读取单项,未传时返回整个 localStorage 的 JSON 字符串,放在 data.value。客户端若需要对象,应再解析该字符串,而不是假定 data.value 本身已经是对象。
set_local_storage 调用 localStorage.setItem;clear_local_storage 调用 localStorage.clear。它们作用于当前页面的 origin。共享上下文中,同源页签会看到同一份持久化数据;换到另一个域名后,读到的不是原站点数据。
不透明 origin 或受限制页面可能拒绝存储访问。先导航到需要测试的本地站点,不要在空白页上用失败结果判断存储实现坏了。
3. 设置命令的真实作用域
| 命令 | 调用对象 | 实现和影响 |
|---|---|---|
set_viewport | Page | setViewportSize,修改当前页 CSS 视口,返回 width/height |
set_media | Page | emulateMedia,设置 light/dark/no-preference,不是操作系统主题 |
set_geolocation | Context | 先授予 geolocation 权限,再设置经纬度 |
set_offline | Context | setOffline,影响共享上下文网络状态 |
set_headers | Context | 解析 headersJson 为字符串映射,调用 setExtraHTTPHeaders |
set_credentials | Context 创建配置 | HTTP 基本认证参数需要重建上下文,服务会检查任务数和启动方式 |
headersJson 是一个包含 JSON 文本的字符串,不是 params 内任意嵌套对象:
{"id":"1001","method":"set_headers","params":{"headersJson":"{\"X-Demo-Mode\":\"fixture\"}"}}
set_credentials 不是网站登录表单填用户名密码。当前实现只允许具备可重建配置、且没有其他任务会受影响时执行;CDP 接入路径可能没有可重建的持久上下文选项,会明确拒绝。
4. 验证与恢复
使用两个同源页签和一个不同源页签测试 Cookie、localStorage 的共享边界。视口与主题测试则验证只改变当前 Page。设置离线、请求头或地理位置后记录原始配置,在测试结束恢复,避免影响后续任务。涉及真实共享 profile 时,不能把 clear_cookies 当作普通的无损重置。
注册参数与 Java 入口
以下按 CommandTable 实际读取参数整理。* 表示注册层使用必填读取器;其余字段省略后由服务决定默认行为。带条件的入口仍需满足正文说明,例如上传文件来源、元素定位二选一。外层 id 不重复列出。
| 命令 | params 字段 | Java 入口 |
|---|---|---|
get_cookies | url | getCookies |
set_cookie | name、value、url | setCookie |
clear_cookies | 无 | clearCookies |
get_local_storage | key | getLocalStorage |
set_local_storage | key*、value | setLocalStorage |
clear_local_storage | 无 | clearLocalStorage |
set_viewport | width、height | setViewport |
set_geolocation | latitude、longitude | setGeolocation |
set_offline | offline | setOffline |
set_headers | headersJson* | setHeaders |
set_credentials | username、password | setCredentials |
set_media | colorScheme* | setMedia |
当前源码:命令注册与执行
先在本章上半部分理解行为,再按命令展开实现。注册代码说明 JSON 参数如何传给 Java;服务方法展示实际浏览器操作。方法依赖共享类中的字段和辅助函数,不应脱离原类直接粘贴编译。
get_cookies
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("get_cookies", (svc, id, a) -> svc.getCookies(id, optStr(a, "url")));
展开 getCookies 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo getCookies(Long browserId, String url) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
List<Cookie> cookies = (url == null || url.isEmpty()) ? inst.context.cookies() : inst.context.cookies(url);
List<Kv> result = new ArrayList<>();
for (Cookie cookie : cookies) {
result.add(Kv.by("name", cookie.name).set("value", cookie.value).set("domain", cookie.domain)
.set("path", cookie.path).set("expires", cookie.expires).set("httpOnly", cookie.httpOnly)
.set("secure", cookie.secure).set("sameSite", cookie.sameSite == null ? null : cookie.sameSite.name()));
}
return RespBodyVo.ok(Kv.by("cookies", result).set("count", result.size()));
}
set_cookie
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_cookie", (svc, id, a) -> svc.setCookie(id, reqStr(a, "name"), reqStr(a, "value"), optStr(a, "url")));
展开 setCookie 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setCookie(Long browserId, String name, String value, String url) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
Cookie cookie = new Cookie(name, value);
if (url != null && !url.isEmpty()) {
cookie.setUrl(url);
}
try {
inst.context.addCookies(Arrays.asList(cookie));
} catch (PlaywrightException e) {
return RespBodyVo.fail("set_cookie 失败:" + briefMessage(e.getMessage()));
}
return RespBodyVo.ok();
}
clear_cookies
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("clear_cookies", (svc, id, a) -> svc.clearCookies(id));
展开 clearCookies 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo clearCookies(Long browserId) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
inst.context.clearCookies();
return RespBodyVo.ok();
}
get_local_storage
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("get_local_storage", (svc, id, a) -> svc.getLocalStorage(id, optStr(a, "key")));
展开 getLocalStorage 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo getLocalStorage(Long browserId, String key) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
Object value = inst.page.evaluate("(key) => key ? localStorage.getItem(key) : JSON.stringify(localStorage)",
key == null ? "" : key);
return RespBodyVo.ok(Kv.by("value", value));
} catch (PlaywrightException e) {
return RespBodyVo.fail("get_local_storage 失败:" + briefMessage(e.getMessage()));
}
}
set_local_storage
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_local_storage", (svc, id, a) -> svc.setLocalStorage(id, reqStr(a, "key"), optStr(a, "value")));
展开 setLocalStorage 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setLocalStorage(Long browserId, String key, String value) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
inst.page.evaluate("([k, v]) => localStorage.setItem(k, v)", Arrays.asList(key, value));
return RespBodyVo.ok();
} catch (PlaywrightException e) {
return RespBodyVo.fail("set_local_storage 失败:" + briefMessage(e.getMessage()));
}
}
clear_local_storage
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("clear_local_storage", (svc, id, a) -> svc.clearLocalStorage(id));
展开 clearLocalStorage 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo clearLocalStorage(Long browserId) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
inst.page.evaluate("() => localStorage.clear()");
return RespBodyVo.ok();
} catch (PlaywrightException e) {
return RespBodyVo.fail("clear_local_storage 失败:" + briefMessage(e.getMessage()));
}
}
set_viewport
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_viewport", (svc, id, a) -> svc.setViewport(id, reqInt(a, "width"), reqInt(a, "height")));
展开 setViewport 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setViewport(Long browserId, int width, int height) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
inst.page.setViewportSize(width, height);
return RespBodyVo.ok(Kv.by("width", width).set("height", height));
}
set_geolocation
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_geolocation", (svc, id, a) -> svc.setGeolocation(id, reqDouble(a, "latitude"), reqDouble(a, "longitude")));
展开 setGeolocation 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setGeolocation(Long browserId, double latitude, double longitude) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
inst.context.grantPermissions(Arrays.asList("geolocation"));
inst.context.setGeolocation(new Geolocation(latitude, longitude));
return RespBodyVo.ok();
} catch (PlaywrightException e) {
return RespBodyVo.fail("set_geolocation 失败:" + briefMessage(e.getMessage()));
}
}
set_offline
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_offline", (svc, id, a) -> svc.setOffline(id, optBool(a, "offline")));
展开 setOffline 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setOffline(Long browserId, boolean offline) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
inst.context.setOffline(offline);
return RespBodyVo.ok(Kv.by("offline", offline));
}
set_headers
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_headers", (svc, id, a) -> svc.setHeaders(id, reqStr(a, "headersJson")));
展开 setHeaders 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setHeaders(Long browserId, String headersJson) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
JSONObject obj = JSON.parseObject(headersJson);
Map<String, String> headers = new LinkedHashMap<>();
for (String key : obj.keySet()) {
headers.put(key, String.valueOf(obj.get(key)));
}
inst.context.setExtraHTTPHeaders(headers);
return RespBodyVo.ok(Kv.by("headers", headers));
} catch (Exception e) {
return RespBodyVo.fail("set_headers 失败:" + briefMessage(e.getMessage()));
}
}
set_credentials
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_credentials", (svc, id, a) -> svc.setCredentials(id, reqStr(a, "username"), reqStr(a, "password")));
展开 setCredentials 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setCredentials(Long browserId, String username, String password) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
if (inst.opts == null) {
// opts 为空 = 这次浏览器是「自己拉进程 + CDP 接上」起来的(用户自己的 Chrome profile,或 Edge):
// 这种上下文的创建参数不在我们手里,HTTP 认证凭据没地方设
SharedBrowser shared = sharedBrowser;
boolean edge = shared != null && shared.resolvedType.isEdge();
return RespBodyVo.fail("set_credentials 失败:当前浏览器走的是「自己拉进程 + CDP 接入」这条启动路径("
+ (edge ? "browser=edge" : "用用户自己的 Chrome profile") + "),HTTP 认证凭据只能在 Playwright "
+ "创建上下文时设置,这条路径上没法重建上下文"
+ (edge ? ";需要 HTTP 基本认证时改用 browser=chrome 或 browser=chromium(托管 profile 那条路)" : ""));
}
if (INSTANCES.size() > 1) {
return RespBodyVo.fail("set_credentials 会重建整个浏览器,而所有任务共用同一个浏览器与 profile;请先 close 掉其它任务再试");
}
inst.opts.setHttpCredentials(new HttpCredentials(username, password));
restartContext(inst);
return RespBodyVo.ok(Kv.by("restarted", true));
}
set_media
展开参数注册
源码:playwright-server/src/main/java/nexus/io/ai/browser/actions/registry/CommandTable.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
put("set_media", (svc, id, a) -> svc.setMedia(id, reqStr(a, "colorScheme")));
展开 setMedia 实现
源码:playwright-server/src/main/java/nexus/io/ai/browser/service/PlaywrightService.java。以下为当前实现,可放回原类中阅读;依赖同类字段和辅助方法,并非独立编译单元。
public RespBodyVo setMedia(Long browserId, String colorScheme) {
BrowserInstance inst = INSTANCES.get(browserId);
if (inst == null) {
return notFound(browserId);
}
try {
ColorScheme scheme = "dark".equalsIgnoreCase(colorScheme) ? ColorScheme.DARK
: "light".equalsIgnoreCase(colorScheme) ? ColorScheme.LIGHT : ColorScheme.NO_PREFERENCE;
inst.page.emulateMedia(new Page.EmulateMediaOptions().setColorScheme(scheme));
return RespBodyVo.ok(Kv.by("colorScheme", scheme.name()));
} catch (PlaywrightException e) {
return RespBodyVo.fail("set_media 失败:" + briefMessage(e.getMessage()));
}
}
