API Tutorials

reCAPTCHA v3 action 参数详解:取值定位与传参

分数 0.9、successtrue,表单一提交却回 403 —— 接入 reCAPTCHA v3 最常见的卡点,问题几乎都出在 action:提交的值和后端预期的对不上。

action 是标明校验场景的字符串,如 logincheckoutsubmit_form。它写进 token,后端逐字比对,对不上就丢弃 —— 和 sitekey、pageurl 一样必填。


30 秒排查清单

“分数正常但被拒”按顺序查,多数在第二步定位:

  • 确认 grecaptcha 已加载,token 不是空串
  • 找出前端 grecaptcha.execute() 传入的 action
  • 原样填进识别请求,大小写、下划线都别改

action 在一次 v3 校验中的位置

前端调用 grecaptcha.execute() 时带上 action:

grecaptcha.execute('SITEKEY', { action: 'submit_form' });

该字符串嵌入 token。后端拿 token 向 Google 校验,响应如下:

{
  "success": true,
  "score": 0.9,
  "action": "submit_form",
  "challenge_ts": "2024-01-15T12:00:00Z",
  "hostname": "example.com"
}

决定放行的是 response.action === 'submit_form'。填成 action: 'homepage' 时 token 依然合法、分数也不低,但比对失败,后端通常只回 403。

排查顺序:先看 success,再看 score,最后看 action。前两项正常不代表 token 能用。


三种方法定位站点真实的 action

哪个先出结果用哪个:

方法 1:网络面板抓调用

  1. 打开 DevTools → 网络 面板
  2. recaptchaanchor 过滤请求
  3. 触发表单提交
  4. 在“发起者”列找 grecaptcha.execute 调用栈,action 就在参数里

方法 2:控制台扫内联脚本

// In the browser console:
document.querySelectorAll('script').forEach(s => {
  if (s.textContent.includes('action')) {
    const match = s.textContent.match(/action['":\s]+['"](\w+)['"]/);
    if (match) console.log('Found action:', match[1]);
  }
});

方法 3:Sources 全局搜索

  1. 打开 DevTools → Sources 面板
  2. Ctrl + Shift + F 全局搜索 grecaptcha.executeaction:
  3. 选项对象里的那个字符串就是 action

内联脚本压缩后常搜不到,但 action 在构建产物里一般是明文。


把 action 带进 CaptchaAI 识别请求

actiongooglekeypageurl 一起提交到 in.php,再每 5 秒轮询 res.php

Python

import requests
import time

response = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "version": "v3",
    "googlekey": "6LfZil0UAAAAADM1Dpz...",
    "action": "login",          # Must match the site's action
    "pageurl": "https://staging.example.com/qa-login",
    "json": 1
})

task_id = response.json()["request"]

for _ in range(30):
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY", "action": "get", "id": task_id, "json": 1
    }).json()
    if result.get("status") == 1:
        token = result["request"]
        break

res.phpaction=get 是 CaptchaAI 接口自身的动作名,与 reCAPTCHA 的 action 同名不同义,别共用变量。

Node.js

const axios = require('axios');

async function solveRecaptchaV3(sitekey, pageurl, action) {
  const submit = await axios.get('https://ocr.captchaai.com/in.php', {
    params: {
      key: 'YOUR_API_KEY',
      method: 'userrecaptcha',
      version: 'v3',
      googlekey: sitekey,
      action: action,
      pageurl: pageurl,
      json: 1
    }
  });

  const taskId = submit.data.request;

  for (let i = 0; i < 30; i++) {
    await new Promise(r => setTimeout(r, 5000));
    const result = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: 'YOUR_API_KEY', action: 'get', id: taskId, json: 1 }
    });
    if (result.data.status === 1) return result.data.request;
  }
  throw new Error('Timeout waiting for solution');
}

solveRecaptchaV3('6LfZil0UAAAAADM1Dpz...', 'https://staging.example.com/qa-login', 'login')
  .then(token => console.log('Token:', token));

建议把 action 按环境和路由整理成配置表,别写死在脚本里:改版换名很常见。


取值速查

常见 action 取值

action 值 典型场景
homepage 落地页访问
login 登录表单
register 账号注册
checkout 支付页

传错值分别会发生什么

情况 结果
与站点一致 通过校验,请求放行
写错 token 有效,但值不匹配被拒
留空 部分站点放行,部分直接拒绝
找不到 先用 homepage 兜底

一个国内团队踩过的坑

深圳一家跨境电商团队跑注册回归测试:staging 的 action 是 register,灰度页面复用同一模板却写成 signup,结果 staging 全绿、灰度全挂,日志只有 403。这类排查还有两点:

  • reCAPTCHA 依赖 Google 托管脚本,内地网络加载不稳定,超时易被误判成 action 配错
  • CaptchaAI 按线程计费而非按次计费(BASIC $15/月,5 线程),反复核对不额外计费

把回显的 action 写进日志并与提交值做断言,改版当天就能发现。


常见问题

后端回显的 action 和我提交的不一致,是识别错了吗?

不是。Google 会把 token 里的 action 原样回显。不一致说明提交的值和页面调用的不同,回 grecaptcha.execute 处核对即可。

action 区分大小写吗?下划线能换连字符吗?

区分,也不能换。后端做字符串全等比较,Submit_Formsubmit_form 是两个值,务必复制原文。

单页应用里 action 动态传入,怎么抓?

grecaptcha.execute 上打断点或监听 XHR,就能看到调用时机和传入的 action。SPA 同一页面常有多个 action,别抓第一个就收工。


相关指南

该文章已禁用评论。