使用 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:可行方法 。
关键洞察 — Vladlen Vlasov, 开发与 Web 安全专家
“向站点中添加 reCAPTCHA 的开发者,与在自动化流水线中遇到它的自动化工程师,解决的是镜像式的问题。理解这两个方面,会让您在每一方面都做得更好:更严密的服务器端集成更难被绕过,而结构良好的 solver API 集成在令牌过期或页面变化时也会更可靠。”