Next.js Route Handlerからソルバーを呼び出す

著者:solvethree読了時間:1分

サーバー側のPOSTハンドラーでタスクを一度だけ作成し、そのIDを使ってGETで取得します。solvethreeのキーはサーバー側で保持してください。ブラウザーからソルバーを直接呼び出したり、待機時間が切れるたびに別のタスクを作成したりしないでください。

このページの内容

サーバーとサイトプロファイルを設定する

  • Node.js 22+と公式JavaScript SDKを使用します。ドキュメントに記載されたパッケージURLからのインストール手順に従ってください。npmレジストリにパッケージがあるとは限りません。
  • サーバー環境にSOLVETHREE_API_KEY、CAPTCHA_SITE、SOLVETHREE_PROXY、INTEGRATION_KEYを設定します。どちらのシークレットにもNEXT_PUBLIC_プレフィックスを付けないでください。
  • ルートを呼び出す前に、ワークスペースで対象ホスト名のプロファイルを有効にしてください。CAPTCHA_SITEを設定してもプロファイルは作成されません。サイトプロファイルの設定を参照してください。
  • サンプルのloginアクションを、連携で必要なアクションに置き換えてください。このリクエストは1つのプロキシを使用し、デフォルトはreCAPTCHA Enterprise v3です。typeフィールドやurlフィールドは不要です。

作成・取得ハンドラーを追加する

サンプルをapp/api/captcha/route.jsに配置します。App RouterのHTTPハンドラーをエクスポートし、SDK用にNode.jsランタイムを明示的に選択します。静的生成リソースではなく、リクエスト時に実行されるサーバールートとして使用してください。

app/api/captcha/route.js · 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. 1.

    作成したタスクを呼び出し元に関連付ける

    認証済みのPOSTでタスクを作成したら、IDを返す前に、認証済みユーザーまたはテナントに関連付けて保存してください。論理的なrequestIdも同じ所有者に関連付け、復旧時に所有権の記録が失われないようにします。

  2. 2.

    取得前に所有権を確認する

    GETでは呼び出し元を認証し、getTaskを呼び出す前に、指定されたIDを所有権の記録と照合します。呼び出し元が所有していないIDは拒否し、このチェックに成功した場合にのみ結果を返してください。

アプリケーションが呼び出し元による選択を明示的に許可していない限り、サイト、アクション、プロキシはサーバー側で管理してください。このサンプルでは環境変数の値を固定しているため、クライアントはこれらの入力を変更できません。

同じタスクをポーリングし、結果が不明なリクエストを復旧する

  1. 1.

    終了状態になるまで同じタスクをポーリングする

    pendingまたはsolvingの場合は、アプリケーション全体の期限内で同じIDを再度取得してください。GETの待機が終了しても、別のタスクを作成する理由にはなりません。

  2. 2.

    readyまたはfailedで停止する

    使用可能な解決結果が含まれるのはreadyだけです。failedの場合はポーリングを停止し、errorCodeとerrorを確認してください。失敗した解決処理は返金されます。レスポンスをタスクとして解釈する前に、成功以外のHTTPレスポンスを処理してください。ルートのcatchハンドラーがあっても、返されたタスクのステータス確認は必要です。

  3. 3.

    接続タイムアウト後にタスク作成を復旧する

    POSTの前にx-request-idを決めて保持してください。タスクIDを受け取っている場合は、そのタスクを取得します。作成レスポンスが失われた場合は、同じリクエストIDと変更していないタスク入力でPOSTを再送し、既存のタスクを復旧してください。リクエストIDには1–64文字のASCII英字、数字、アンダースコア、ハイフンを使用できます。同じIDを異なる入力に再利用すると競合します。

タスクがreadyであることは、solvethreeが解決結果を生成したことを意味し、対象がそれを受け入れたことを意味するわけではありません。SDKは代わりに送信しません。送信時は、返されたuserAgentとsecChUaを、解決に成功したプロキシとともに使用してください。この単一プロキシのサンプルでは、設定済みのプロキシです。無関係なブラウザー識別情報やIPに切り替えないでください。

リクエストエラーやタスクの最終的な失敗が発生した場合は、別の解決処理に料金を支払う前にAPIエラーリファレンスを確認してください。無効な入力を変更せずに再試行しても解決しません。

最初のタスクを実行しましょう。

$5のワークスペースクレジットで始められます。

ワークスペースを作成
Next.js Route Handlerからソルバーを呼び出す · solvethree