从 Next.js 路由处理程序调用求解器
使用服务端 POST 处理程序创建一次任务,然后通过 GET 按任务 ID 获取任务。将 solvethree 密钥保留在服务器上;浏览器不应直接调用求解服务,也不应在每次等待结束后创建新任务。
本页内容
设置服务器和站点配置
- 使用 Node.js 22+ 和官方 JavaScript SDK。按照文档中的包 URL 安装方式操作;不要假定 npm 注册表中有可用的包。
- 在服务器环境中设置 SOLVETHREE_API_KEY、CAPTCHA_SITE、SOLVETHREE_PROXY 和 INTEGRATION_KEY。不要为这两个密钥中的任何一个添加 NEXT_PUBLIC_ 前缀。
- 调用路由前,先在工作区中激活目标主机名对应的配置。设置 CAPTCHA_SITE 不会创建配置;请参阅站点配置设置。
- 将示例中的 login 操作替换为集成所需的操作。请求使用一个代理,默认为 reCAPTCHA Enterprise v3;不需要 type 或 url 字段。
添加创建和获取任务的处理程序
将示例放在 app/api/captcha/route.js 中。它导出 App Router HTTP 处理程序,并为 SDK 显式选择 Node.js 运行时。将其保留为在请求时执行的服务端路由,不要设为静态生成的资源。
import { Solvethree, SolvethreeError } from '@solvethree/sdk';
export const runtime = 'nodejs';
const client = new Solvethree({ apiKey: process.env.SOLVETHREE_API_KEY });
function authorized(request) {
const key = process.env.INTEGRATION_KEY;
return Boolean(key) && request.headers.get('x-integration-key') === key;
}
function failure(error) {
return error instanceof SolvethreeError
? Response.json({ requestId: error.requestId, taskId: error.taskId }, { status: 502 })
: Response.json({ error: 'Invalid task input or ID' }, { status: 400 });
}
export async function POST(request) {
if (!authorized(request)) return new Response('Unauthorized', { status: 401 });
try {
return Response.json(await client.createTask({
site: process.env.CAPTCHA_SITE, action: 'login', proxy: process.env.SOLVETHREE_PROXY,
requestId: request.headers.get('x-request-id') ?? undefined,
}, { waitMs: 0, signal: AbortSignal.timeout(20000) }));
} catch (error) { return failure(error); }
}
export async function GET(request) {
if (!authorized(request)) return new Response('Unauthorized', { status: 401 });
const id = new URL(request.url).searchParams.get('id');
if (!id) return Response.json({ error: 'Provide id' }, { status: 400 });
try {
return Response.json(await client.getTask(id, { waitMs: 15000, signal: AbortSignal.timeout(25000) }));
} catch (error) { return failure(error); }
}POST 使用 waitMs: 0 调用 createTask,因此会直接返回任务响应,而不等待求解结果。请保存返回的任务 ID。GET 需要此现有 ID,并调用 getTask;它绝不会创建任务。
GET 请求最多等待 15 秒,并另设 25 秒的请求中止时限。POST 的请求中止时限为 20 秒。这些限制针对每个请求,而不是任务的生命周期。
返回任务前逐一检查访问权限
对于浏览器访问,请使用应用实际的服务端身份验证机制,而不是分发 INTEGRATION_KEY。仅验证身份还不够:如果接受已通过身份验证的用户提供的任意任务 ID,他们仍然可以请求他人的结果。
- 1.
将创建的任务与调用者关联
经过身份验证的 POST 创建任务后,在返回前将其 ID 与已验证的用户或租户关联存储。同时将逻辑 requestId 与该所有者关联,以免恢复时丢失归属记录。
- 2.
获取前检查归属
处理 GET 时,先验证调用者身份,并根据归属记录检查所提供的 ID,然后再调用 getTask。拒绝不属于调用者的 ID,只有检查通过后才返回结果。
除非应用明确授权调用者选择,否则应由服务器控制站点、操作和代理。此示例中的固定环境值可防止客户端更改这些输入。
轮询同一任务并恢复结果不确定的请求
- 1.
继续轮询尚未进入终态的任务
对于 pending 或 solving 状态,在应用的总体截止时间内再次获取同一 ID 的任务。GET 等待结束并不是创建新任务的理由。
- 2.
在 ready 或 failed 时停止
只有 ready 状态包含可用的求解结果。对于 failed,停止轮询并检查 errorCode 和 error;求解失败会退款。在将响应作为任务解析前,先处理非成功 HTTP 响应。路由的 catch 处理程序不能替代对返回任务状态的检查。
- 3.
连接超时后恢复创建请求
在 POST 前选定并保存 x-request-id。如果已收到任务 ID,则获取该任务。如果创建响应丢失,则使用相同的请求 ID 和未更改的任务输入再次发送 POST,以恢复现有任务。请求 ID 允许包含 1–64 个 ASCII 字母、数字、下划线或连字符;将同一 ID 用于不同输入会产生冲突。
任务处于 ready 状态表示 solvethree 已生成求解结果,并不表示目标已接受该结果。SDK 不会代你提交。提交时,使用返回的 userAgent 和 secChUa,并使用求解成功时所用的代理,也就是此单代理示例中配置的代理。不要切换到无关的浏览器身份或 IP。
遇到请求错误或终态失败时,请先查阅 API 错误参考,再付费进行另一次求解。原样重试无效输入无法解决问题。
来源与 API 参考
运行您的第一个任务。
使用 $5 工作区额度开始体验。