You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google reCAPTCHA v2本地运行正常 部署线上网站始终验证失败

ASP.NET MVC 线上部署Google reCAPTCHA v2验证失败排查方案

问题背景

  • 基于ASP.NET MVC搭建的网站本地集成Google reCAPTCHA v2(复选框版本),本地localhost环境功能运行完全正常
  • 项目迁移部署到线上后,验证码可正常渲染、支持复选框点击交互,但服务端验证环节始终失败
  • 已确认线上部署代码与本地完全一致,且已替换为对应环境的site key和secret key

现有实现代码

视图(View)代码

<div class="g-recaptcha" data-sitekey="my_site_key"></div>

<div class="submit-frm-btn">
    <button class="contact-btn bg-mediumBlue"
            type="submit">
        Submit
    </button>
</div>

控制器(Controller)代码

public ActionResult SaveForm(ContactUs contactUsForm)
{
    // 获取验证码响应参数
    var response = Request["g-recaptcha-response"];
    string secretkey = "my_secret_key";
    var client = new WebClient();
 
    var result = client.DownloadString(string.Format("https://www.google.com/recaptcha/api/siteverify?secret=" + secretkey + "&response=" + response  +""));
    var obj = JObject.Parse(result);
    var status = (bool)obj.SelectToken("success");
    ViewData["Message"] = status ? "Google reCaptcha validation success." : "Google reCaptcha validation failed.";

    // 验证通过后执行业务逻辑
    if (status)
    {
        if (ModelState.IsValid)
        {
            // 表单入库逻辑
        }
    }
}

排查思路与解决方案

按出现概率从高到低排序:

  • 检查reCAPTCHA后台域名配置
    本地localhost属于reCAPTCHA默认放行的测试域名,无需手动配置即可使用。线上环境必须登录reCAPTCHA管理后台,找到对应生产环境密钥的配置页,将线上域名(不带协议头、不带路径,例如example.com、www.example.com)添加到「允许的域名」列表,保存后等待3-5分钟生效即可。这是该问题最高发的原因。
  • 确认线上服务器可正常访问reCAPTCHA验证接口
    现有代码中服务端验证是由你的线上服务器主动请求https://www.google.com/recaptcha/api/siteverify接口完成的,和用户端能否正常加载验证码脚本无关。如果你的线上服务器存在网络出口限制、无法连通Google服务,会直接导致请求失败、拿不到正确的验证结果。
    排查方法:直接登录线上服务器,测试能否正常访问上述siteverify接口;同时给现有验证逻辑加异常捕获和日志,记录接口返回的完整内容(尤其是error-codes字段),根据返回的错误码可以直接定位具体原因。
  • 修复参数拼接的编码问题
    现有代码直接将g-recaptcha-response参数值拼接在URL中,未做URL编码。该参数值是长度较长、包含特殊字符的加密字符串,线上环境如果存在URL重写、WAF拦截、编码规则不一致的情况,很容易出现参数被截断、转义错误的问题,导致Google接口收到无效的响应值,直接返回验证失败。
    建议将验证请求改为官方推荐的POST方式提交,同时对参数做标准编码,避免拼接带来的异常。
  • 确认线上实际加载的密钥配置正确
    虽然已手动替换密钥,但需要排查发布过程中是否存在配置文件被覆盖、配置转换规则错误、密钥带多余空格/换行的问题。可以临时在服务端验证逻辑前加日志,输出当前运行环境实际读取到的site key和secret key,确认和reCAPTCHA后台生成的生产环境密钥完全配对,没有混用测试环境密钥。
  • 排查中间件拦截问题
    如果线上服务器部署了WAF、反向代理、CDN服务,检查是否存在拦截g-recaptcha-response表单参数、篡改出站请求到siteverify接口的规则,这类拦截也会导致参数传递异常、验证失败。

代码优化参考

将原有GET拼接请求改为POST提交,增加异常捕获和错误日志,参考代码如下:

public ActionResult SaveForm(ContactUs contactUsForm)
{
    var captchaResponse = Request["g-recaptcha-response"];
    var secretKey = "你的生产环境secret key"; // 建议从配置文件读取,不要硬编码
    var isSuccess = false;
    var errorMsg = string.Empty;

    try
    {
        if (string.IsNullOrEmpty(captchaResponse))
        {
            errorMsg = "未获取到验证码响应";
        }
        else
        {
            using (var client = new WebClient())
            {
                // 官方推荐POST方式提交验证,避免GET参数编码问题
                var pars = new NameValueCollection
                {
                    { "secret", secretKey },
                    { "response", captchaResponse },
                    { "remoteip", Request.UserHostAddress } // 可选,传用户IP提升验证准确率
                };
                var responseBytes = client.UploadValues("https://www.google.com/recaptcha/api/siteverify", "POST", pars);
                var result = System.Text.Encoding.UTF8.GetString(responseBytes);
                var obj = JObject.Parse(result);
                isSuccess = (bool)obj.SelectToken("success");
                if (!isSuccess)
                {
                    // 记录错误码,方便排查
                    var errorCodes = string.Join(",", obj.SelectToken("error-codes")?.ToObject<string[]>() ?? new string[0]);
                    errorMsg = $"验证码验证失败,错误码:{errorCodes}";
                }
            }
        }
    }
    catch (Exception ex)
    {
        errorMsg = $"请求验证码验证接口异常:{ex.Message}";
        // 这里记录服务端日志
    }

    ViewData["Message"] = isSuccess ? "Google reCaptcha validation success." : $"Google reCaptcha validation failed. {errorMsg}";

    if (isSuccess && ModelState.IsValid)
    {
        // 表单入库逻辑
    }
    return View(contactUsForm);
}

常见error-codes说明:

  • missing-input-secret:secret参数缺失
  • invalid-input-secret:secret key无效
  • missing-input-response:验证码响应参数缺失
  • invalid-input-response:验证码响应参数无效
  • bad-request:请求格式错误
  • timeout-or-duplicate:验证码已过期或已被使用

内容的提问来源于stack exchange,提问作者Kyle

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 23:39:34