在 Playwright JSON 请求中提交求解得到的令牌

作者:solvethree阅读需 1 分钟

拦截应用已知的 JSON POST 请求,并将其 CAPTCHA 字段替换为 solution.token。如果应用根据 JavaScript 状态构建请求,填写文本区域也无济于事。

以下示例针对自有应用的同源提交端点。它会保留其他 JSON 字段和请求头,而不是重新构建请求。

本页内容

根据你的应用调整示例

  1. 1.

    准备求解器

    使用 Node.js 22+、Playwright 和官方 JavaScript SDK。请遵循 SDK 安装说明,使用文档中提供的软件包下载方式,不要假定 npm 注册表中有该软件包。将 SOLVETHREE_API_KEY 保存在 Node.js 进程中,而不是浏览器代码中。

  2. 2.

    配置站点和代理

    将 TARGET_URL 设置为你拥有的测试页面,将 SOLVETHREE_PROXY 设置为该页面使用的 HTTP 或 HTTPS 代理 URL。示例针对页面的主机名请求 login 操作。该主机名需要有效的工作区配置;请先配置站点配置文件。如果应用使用其他操作,请相应修改。

  3. 3.

    确定具体的提交请求

    将 TARGET_SUBMIT_URL 设置为 JSON POST 端点,包含其路径。它必须与页面同源。示例要求请求对象包含 recaptchaToken,且按钮的无障碍名称必须恰好为 Submit。请一并修改这些与具体应用相关的设置。

作为测试夹具,请使用一个向该端点发送 JSON 对象并返回可检查响应的页面。加入另一个字段和一个 CSRF 字段,以便确认这两个字段均未发生变化。仅回显请求的本地测试夹具可以演示 JSON 改写,但无法验证 CAPTCHA 是否被接受。提供的示例仍会执行真实的求解,因此需要一个已配置且可通过代理访问的站点。

求解、拦截并提交

Playwright · 替换一个已知的 JSON 令牌参数
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 错误处理。

运行您的第一个任务。

使用 $5 工作区额度开始体验。

创建工作区
在 Playwright JSON 请求中提交求解得到的令牌 · solvethree