在 Playwright JSON 请求中提交求解得到的令牌
拦截应用已知的 JSON POST 请求,并将其 CAPTCHA 字段替换为 solution.token。如果应用根据 JavaScript 状态构建请求,填写文本区域也无济于事。
以下示例针对自有应用的同源提交端点。它会保留其他 JSON 字段和请求头,而不是重新构建请求。
本页内容
根据你的应用调整示例
- 1.
准备求解器
使用 Node.js 22+、Playwright 和官方 JavaScript SDK。请遵循 SDK 安装说明,使用文档中提供的软件包下载方式,不要假定 npm 注册表中有该软件包。将
SOLVETHREE_API_KEY保存在 Node.js 进程中,而不是浏览器代码中。 - 2.
配置站点和代理
将
TARGET_URL设置为你拥有的测试页面,将SOLVETHREE_PROXY设置为该页面使用的 HTTP 或 HTTPS 代理 URL。示例针对页面的主机名请求login操作。该主机名需要有效的工作区配置;请先配置站点配置文件。如果应用使用其他操作,请相应修改。 - 3.
确定具体的提交请求
将
TARGET_SUBMIT_URL设置为 JSON POST 端点,包含其路径。它必须与页面同源。示例要求请求对象包含recaptchaToken,且按钮的无障碍名称必须恰好为Submit。请一并修改这些与具体应用相关的设置。
作为测试夹具,请使用一个向该端点发送 JSON 对象并返回可检查响应的页面。加入另一个字段和一个 CSRF 字段,以便确认这两个字段均未发生变化。仅回显请求的本地测试夹具可以演示 JSON 改写,但无法验证 CAPTCHA 是否被接受。提供的示例仍会执行真实的求解,因此需要一个已配置且可通过代理访问的站点。
求解、拦截并提交
import { chromium } from 'playwright';
import { Solvethree } from '@solvethree/sdk';
const client = new Solvethree({ apiKey: process.env.SOLVETHREE_API_KEY });
const target = new URL(process.env.TARGET_URL);
const proxy = new URL(process.env.SOLVETHREE_PROXY);
const result = await client.solve({ site: target.hostname, action: 'login', proxy: process.env.SOLVETHREE_PROXY });
const proxyConfig = { server: `${proxy.protocol}//${proxy.host}`, username: decodeURIComponent(proxy.username), password: decodeURIComponent(proxy.password) };
const submit = new URL(process.env.TARGET_SUBMIT_URL);
if (submit.origin !== target.origin) throw new Error('Use this demo with a same-origin submission URL');
const browser = await chromium.launch();
try {
const context = await browser.newContext({ proxy: proxyConfig, userAgent: result.solution.userAgent,
extraHTTPHeaders: { 'sec-ch-ua': result.solution.secChUa } });
const page = await context.newPage();
await page.route(submit.href, async route => {
if (route.request().method() !== 'POST') return route.continue();
const body = route.request().postDataJSON();
if (!body || typeof body !== 'object' || Array.isArray(body)) throw new Error('Expected the known JSON object');
await route.continue({ postData: JSON.stringify({ ...body, recaptchaToken: result.solution.token }),
headers: { ...route.request().headers(), 'content-type': 'application/json' } });
});
await page.goto(target.href);
const outcome = page.waitForResponse(r => r.url() === submit.href && r.request().method() === 'POST');
await page.getByRole('button', { name: 'Submit', exact: true }).click();
console.log('Application HTTP status:', (await outcome).status());
// recaptchaToken, the Submit button and this endpoint belong to this demo app.
// Adapt them to the real application, retaining its session/CSRF data.
await context.close();
} finally { await browser.close(); }client.solve 会创建任务并持续轮询,直到任务就绪或抛出异常。随后,示例使用 solution.userAgent、solution.secChUa 以及求解时提供的同一个代理创建浏览器上下文。SDK 不会将求解结果应用到浏览器;这由路由处理程序完成。
浏览器上下文是新建的。如果提交需要身份验证或其他会话设置,请在提交前在此上下文中完成。示例不会导入现有的浏览器会话。
只替换令牌,不替换整个请求
路由会在导航前注册,作用范围仅限于配置的提交 URL。非 POST 请求会原样继续发送。对于 POST 请求,处理程序会读取现有 JSON 对象,复制其字段,并仅替换 recaptchaToken。
这样会保留表单值和 CSRF 数据等请求体字段。处理程序还会复制请求头,并将内容类型设置为 JSON。请保留应用现有的会话和 CSRF 机制;求解得到的令牌不能替代其中任何一项。
不要将路由范围扩大到所有请求,也不要随意替换看起来像令牌的字段。请检查你拥有的应用发出的请求,并使用其实际字段名。此示例不会发现组件、调用任意回调,也不支持任意第三方页面。Playwright 的网络文档介绍了拦截机制。
检查应用响应
响应等待会在点击前开始,并匹配提交 URL 和 POST 方法。日志记录的状态属于应用的响应,而不是 solvethree 任务。请按照应用自身的成功判定规则,检查该响应的正文或应用最终的状态。任务就绪或 HTTP 成功状态本身,都不能证明应用已接受令牌。
- 响应等待始终未完成。
检查指定的 Submit 按钮是否会向配置的 URL 发起 POST 请求。
试试这样做: 修正按钮定位器、端点或方法,使其与应用一致。不要将拦截范围扩大到无关流量。
- 路由无法读取 JSON 对象。
检查请求体和内容类型。
试试这样做: 此处理程序仅适用于已知的 JSON 对象端点。表单数据、数组和其他载荷格式需要采用不同的处理方式。
- 任务已就绪,但应用拒绝提交。
检查发出的 JSON 中是否包含
solution.token,然后检查会话/CSRF 数据、操作、返回的浏览器身份和代理。试试这样做: 在付费进行下一次求解前,先修正不匹配的请求。让浏览器继续使用求解时的代理,并使用返回的身份信息。
- 求解在浏览器打开前失败。
区分 HTTP 请求错误与任务的终止性失败。对于失败的任务,请检查
errorCode和error。试试这样做: 修复报告的输入、配置文件或连接问题,不要使用未更改的输入重试。请参阅 API 错误处理。
来源与 API 参考
运行您的第一个任务。
使用 $5 工作区额度开始体验。