reCAPTCHA v2 API 集成:如何接入和使用
对于 2026 年的 Web 开发者来说,集成 reCAPTCHA v2 API 是一项标准的安全任务。Google 的 reCAPTCHA v2 有两种形式:大家熟悉的“我不是机器人”复选框,以及在后台静默触发的隐形模式。在这两种情况下,其机制都是一样的——客户端小组件会生成一个一次性令牌,而您的服务器会在处理请求之前,通过 Google 的 siteverify API 对其进行验证。
本指南涵盖完整的集成流程:站点注册、HTML 小组件嵌入、服务器端令牌验证,以及常见错误处理。本文还会讨论自动化场景——当 reCAPTCHA v2 出现在无法由人工参与的工作流中时,该如何应对。如需更广泛的概览,请先查看我们的 reCAPTCHA v2 求解页面。
专家观点 — Vladlen Vlasov,开发与 Web 安全专家
“到了 2026 年,reCAPTCHA v2 的集成细节依然重要,正是因为这个小组件部署得如此广泛。服务器端验证步骤处理错误——或者完全跳过它——仍然是我在开发者论坛上看到的最常见安全问题之一。客户端小组件只是整个故事的一半。”
什么是 reCAPTCHA v2,它如何工作?
reCAPTCHA v2 是 Google 提供的一项 CAPTCHA 服务,用于区分真实用户和自动化机器人。它分两个阶段运行:客户端阶段由浏览器渲染小组件,并在用户交互后生成响应令牌;服务器端阶段则由您的后端通过 Google 的 API 验证该令牌。

复选框版本会要求用户点击“我不是机器人”。Google 的风险分析引擎会在后台运行;如果评分处于临界范围,就会显示图片验证挑战。隐形版本则跳过可见复选框,并在配置的操作上自动触发,通常是在表单提交时;只有当风险评分要求这样做时,才会显示挑战。

在做集成决策时,理解 v2 与其其他版本之间的差异非常重要。有关更详细的技术拆解,请参阅 reCAPTCHA v2 vs v3 vs Enterprise: Key Differences。
集成 reCAPTCHA v2 之前的前提条件
在开始编码之前,您需要从 Google 获取两样东西:Site Key 和 Secret Key。
注册您的站点
- 前往 google.com/recaptcha/admin/create,并使用 Google 账号登录。
- 输入标签,选择 reCAPTCHA v2,然后选择复选框版本或隐形版本。
- 在 Domains 下添加您的域名。如果您在本地测试,也请添加 localhost。
- 选择一个现有的 Google Cloud Platform project,或者新建一个。reCAPTCHA Classic 已于 2026 年初迁移到 GCP,因此现在所有密钥都归属于某个 GCP 项目。
- 接受服务条款,然后点击 Submit。

Google 会显示两个密钥:
- Site Key —— 公开,可嵌入到您的 HTML 中。
- Secret Key —— 私密,仅供您的服务器使用。切勿在客户端代码中暴露它。

在生产环境中,您需要使用 HTTPS。reCAPTCHA 在开发阶段可以通过 localhost 上的 HTTP 运行,但在线部署需要安全连接,并且需要具备到 www.google.com 的出站 HTTPS 访问能力以完成验证。
将 reCAPTCHA v2 添加到您的 HTML 表单
加载 reCAPTCHA 脚本
将以下脚本标签放在页面的 <head> 中,或放在结束 </body> 标签之前:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>async defer 属性可防止脚本阻塞页面渲染。
使用 data-sitekey 放置小组件
对于标准复选框版本,请在表单中添加一个带有 g-recaptcha 类和您的 Site Key 的 div:
<form method="POST" action="/submit">
*<!-- your form fields -->*
<div class="g-recaptcha" data-sitekey="YOUR_SITE_KEY"></div>
<button type="submit">Submit</button>
</form>页面加载后,Google 的脚本会将这个 div 替换为交互式小组件。用户成功完成交互后,它会填充一个名为 g-recaptcha-response 的隐藏输入字段,并随表单一起提交。
隐形版本设置
隐形版本附加在您的提交按钮上,而不是渲染一个可见的小组件:
<form method="POST" action="/submit">
*<!-- your form fields -->*
<button
class="g-recaptcha"
data-sitekey="YOUR_SITE_KEY"
data-callback="onSubmit"
data-action="submit"
type="submit">
Submit
</button>
</form>
<script>
function onSubmit(token) {
document.getElementById('your-form-id').submit();
}
</script>data-callback 函数会接收令牌,并触发实际的表单提交。如果没有这个回调,表单在 reCAPTCHA 完成后将不会提交。
使用 siteverify API 进行服务器端验证
嵌入小组件只是安全集成 reCAPTCHA v2 的前半部分。您必须在服务器上验证令牌。未经过验证的令牌无法提供任何机器人防护。
流程很直接:用户与小组件交互 → Google 向浏览器返回一个 g-recaptcha-response 令牌 → 该令牌随表单一起提交到您的服务器 → 您的服务器将令牌和您的 Secret Key 通过 POST 发送到 https://www.google.com/recaptcha/api/siteverify → Google 返回一个 JSON 结果。
向 siteverify 发送 POST 请求
该验证端点接受一个带有两个必需参数的 POST 请求:
| 参数 | 说明 |
| secret | 您的 Secret Key |
| response | 来自客户端的 g-recaptcha-response 令牌 |
| remoteip (可选) | 用户的 IP 地址 |
解析 JSON 响应并处理错误
验证成功时会返回:
{
"success": true,
"challenge_ts": "2026-06-17T10:00:00Z",
"hostname": "yourdomain.com",
"error-codes": []
}验证失败时会返回 "success": false,以及一个或多个错误代码:
| 错误代码 | 含义 |
| missing-input-secret | 未发送 Secret Key 参数 |
| invalid-input-secret | Secret Key 不正确或格式不合法 |
| missing-input-response | 客户端未提交令牌 |
| invalid-input-response | 令牌无效或格式不合法 |
| timeout-or-duplicate | 令牌已过期或已被使用 |
在继续处理之前,始终检查 success === true。不要仅仅依赖没有错误代码这一点。
PHP 服务器端验证示例
下面的示例展示了完整的服务器端验证函数。请将 $YOUR_SECRET_KEY 替换为您的实际 Secret Key。
<?php
declare(strict_types=1);
function verifyRecaptchaV2(
string $token,
string $YOUR_SECRET_KEY,
?string $remoteIp = null
): array {
if ($token === "") {
return [
"ok" => false,
"message" => "reCAPTCHA token was not received.",
"data" => null,
];
}
$postFields = [
"secret" => $YOUR_SECRET_KEY,
"response" => $token,
];
if ($remoteIp !== null && $remoteIp !== "") {
$postFields["remoteip"] = $remoteIp;
}
$ch = curl_init("https://www.google.com/recaptcha/api/siteverify");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($postFields),
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_SSL_VERIFYHOST => 2,
]);
$responseBody = curl_exec($ch);
$curlError = curl_error($ch);
$httpCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($responseBody === false || $curlError !== "") {
return [
"ok" => false,
"message" => "Failed to send a request to Google reCAPTCHA.",
"data" => null,
];
}
if ($httpCode < 200 || $httpCode >= 300) {
return [
"ok" => false,
"message" => "Google reCAPTCHA returned an unexpected HTTP status.",
"data" => null,
];
}
$data = json_decode($responseBody, true);
if (!is_array($data)) {
return [
"ok" => false,
"message" => "Failed to parse the Google reCAPTCHA response.",
"data" => null,
];
}
if (!empty($data["success"])) {
return [
"ok" => true,
"message" => "reCAPTCHA verification passed successfully.",
"data" => $data,
];
}
$errors =
isset($data["error-codes"]) && is_array($data["error-codes"])
? implode(", ", $data["error-codes"])
: "unknown_error";
return [
"ok" => false,
"message" => "reCAPTCHA verification failed: " . $errors,
"data" => $data,
];
}在 JavaScript 中使用 reCAPTCHA v2
集成 reCAPTCHA v2 之后,您可以直接通过 JavaScript API 与该小组件交互。下表涵盖了关键方法和回调。
| 方法 / 回调 | 用途 |
| grecaptcha.render() | 将小组件手动渲染到一个容器元素中 |
| grecaptcha.getResponse() | 获取当前响应令牌(如果尚未完成验证,则为空字符串) |
| grecaptcha.reset() | 重置当前挑战,以便用户再次完成验证 |
| callback | 当用户成功完成挑战时触发;会接收该令牌 |
| expired-callback | 当已完成验证的令牌在提交前过期时触发 |
实用的 JavaScript 示例
获取生成的令牌:
const token = grecaptcha.getResponse();在请求失败后重置小组件:
grecaptcha.reset();动态渲染小组件(适用于 SPA,或容器是在页面加载后注入到 DOM 中的情况):
function onSolved(token) {
document.querySelector('textarea[name="g-recaptcha-response"]').value = token;
document.getElementById('contact-form').submit();
}
grecaptcha.render('captcha-container', {
sitekey: 'YOUR_SITE_KEY',
callback: onSolved,
'expired-callback': () => grecaptcha.reset(),
});在提交前检查用户是否已完成挑战:
if (!grecaptcha.getResponse()) {
alert('Complete the CAPTCHA first.');
return;
}expired-callback 很容易被忽视:如果用户完成了挑战,但在提交前等待超过两分钟,令牌会静默过期。如果没有这个处理程序,您的表单将提交一个无效令牌,并在服务器端验证时因 timeout-or-duplicate 而失败。
常见集成错误及修复方法
即使是看似直接的 reCAPTCHA v2 集成,也可能以一些可预见的方式出问题。
| 问题 | 可能原因 | 修复方法 |
| 小组件未渲染 | 缺少脚本标签,或被 CSP 阻止 | 在您的 CSP script-src 和 frame-src 中添加 https://www.google.com |
| 验证时出现 invalid-input-secret | Secret Key 错误,或来自错误的项目 | 检查 Admin Console,并确认您使用的是正确的 Secret Key |
| timeout-or-duplicate | 令牌已超过 \~2 分钟,或被提交了两次 | 重新提示用户完成验证,并且绝不要重复使用令牌 |
| invalid-input-response | 令牌未转发到服务器 | 记录 req.body['g-recaptcha-response'],以确认它到达了您的处理程序 |
| 控制台中的域名不匹配错误 | 域名未在 Admin Console 中注册 | 在 reCAPTCHA Admin 设置中添加准确的域名 |
| 小组件在 SPA 路由切换后失效 | DOM 操作后未重新渲染小组件 | 调用 grecaptcha.render(),或使用 grecaptcha.reset() 重置 |
| AJAX 表单中出现 missing-input-response | AJAX 负载中未包含令牌字段 | 读取 grecaptcha.getResponse(),并将其附加到您的 fetch 或 XHR 请求体中 |
绝不要将缺失令牌视为已通过验证。如果缺少 g-recaptcha-response,请立即拒绝该请求。
用于自动化的 reCAPTCHA v2:Solver API 方案
您刚刚将 reCAPTCHA v2 添加到您的站点中——现在该测试它在实际环境中的表现了。与其在每次检查时都手动完成挑战,不如将您的 reCAPTCHA 公开参数发送到 CapMonster Cloud,接收一个有效令牌,并使用它来测试您集成中的不同场景。
CapMonster Cloud reCAPTCHA v2 求解 API 遵循四步模式:
- 提交一个任务,其中包含目标页面 URL 和 sitekey。
- 轮询获取结果。
- 将返回的令牌插入到 g-recaptcha-response 中。
- 在令牌过期前提交表单。
CapMonster Cloud 提供了一个 reCAPTCHA v2 solver API,遵循这种返回令牌的模式。如需实际操作演示,请参阅 如何在 2026 年解决 reCAPTCHA v2:可行方法。如果您正在比较不同的服务提供商,文章“如何在 2026 年选择最佳的 ReCAPTCHA v2 求解器”提供了实用的指导。
关键洞察 — Vladlen Vlasov,开发与 Web 安全专家
“向站点中添加 reCAPTCHA 的开发者,与在自动化流水线中遇到它的自动化工程师,解决的是镜像式的问题。理解这两个方面,会让您在每一方面都做得更好:更严密的服务器端集成更难被绕过,而结构良好的 solver API 集成在令牌过期或页面变化时也会更可靠。”
FAQ
结论
正确集成 reCAPTCHA v2 API 需要两个部分:一个正常工作的客户端小组件,以及一个真正用于控制请求处理的服务器端 siteverify 校验。对于大多数项目来说,复选框版本是更稳妥的起点——更容易实现、更容易调试,也更便于用户理解。隐形版本适用于“减少用户操作不便”是可衡量优先目标、并且您的回调流程足够稳固的场景。如果您的自动化工作流需要以编程方式处理 reCAPTCHA v2,那么令牌注入模式是直接明了的——主要约束在于令牌生命周期,因此应尽快获取并提交。
为您的自动化流水线获取 reCAPTCHA v2 令牌
如果您的自动化工作流会大规模遇到 reCAPTCHA v2,手动处理是无法持续的。CapMonster Cloud 提供了一个 reCAPTCHA v2 solver API,适配本指南中描述的同一类集成模式——发送 sitekey 和页面 URL,接收一个可直接使用的令牌。
- 兼容浏览器自动化和直接 HTTP 工作流
- 用于任务创建和结果获取的简洁 API 模式
- 面向与 reCAPTCHA 相关的自动化使用场景构建
请在 reCAPTCHA v2 概览页面 查看支持的 reCAPTCHA v2 工作流。





