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

用户授权后加载reCaptcha V3报错:grecaptcha.ready不是函数

问题描述

我正在实现一个小型Cookie校验工具,要求在用户明确同意前不加载Google reCAPTCHA Enterprise的JS库。但在用户同意后加载库时,出现以下错误:

Uncaught TypeError: grecaptcha.ready is not a function

调用grecaptcha的代码:

<script>
  document.addEventListener("DOMContentLoaded", function() {
    const contactForm = document.getElementById("contact-form");
    const submitButton = document.getElementById("btnSubmit");
    const recaptchaResponseInput = document.getElementById("recaptcha_response");

    submitButton.addEventListener("click", function(event) {
      event.preventDefault();
      grecaptcha.ready(function () {
        grecaptcha.execute('################', { action: 'submit' }).then(function (token) {
            recaptchaResponseInput.value = token;
            contactForm.submit();
        });
      });
    });
  });
</script>

加载reCAPTCHA库的代码:

document.addEventListener("DOMContentLoaded", function() {
        const cookieBanner = document.getElementById("cookie-banner");
        const acceptCookiesButton = document.getElementById("accept-cookies");
        const contactform = document.getElementById("contactform");

        acceptCookiesButton.addEventListener("click", function() {
            // 保存同意状态
            localStorage.setItem("cookieConsent", "true");

            // 加载reCAPTCHA脚本
            $.getScript("https://www.google.com/recaptcha/enterprise.js?render=##############");

            // 隐藏Cookie横幅,显示表单
            cookieBanner.style.display = "none";
            contactform.style.display = "block";
        });
    });

我确认库已正确加载(页面右下角出现reCAPTCHA图标),但错误依然存在。尝试改用动态创建脚本标签并绑定onload事件的方式,问题仍未解决:

<script>
  document.addEventListener("DOMContentLoaded", function() {
    const cookieBanner = document.getElementById("cookie-banner");
    const acceptCookiesButton = document.getElementById("accept-cookies");
    const contactform = document.getElementById("contactform");

    acceptCookiesButton.addEventListener("click", function() {
        // 保存同意状态
        localStorage.setItem("cookieConsent", "true");

        // 加载reCAPTCHA脚本并绑定onload回调
        const script = document.createElement("script");
        script.src = "https://www.google.com/recaptcha/enterprise.js?render=#################";
        script.onload = function() {
            // 绑定表单提交事件
            contactform.addEventListener("submit", function(event) {
                event.preventDefault();
                    grecaptcha.execute('#####################', { action: 'submit' }).then(function (token) {
                        const recaptchaResponseInput = document.getElementById("recaptcha_response");
                        recaptchaResponseInput.value = token;
                        contactform.submit();
                });
            });

            // 隐藏Cookie横幅,显示表单
            cookieBanner.style.display = "none";
            contactform.style.display = "block";
        };
        document.body.appendChild(script);
    });
});
</script>

请问如何解决这个错误?同时有没有更优的方案,能在用户授权前彻底阻止reCAPTCHA脚本加载?

解决方案

错误原因

无论是$.getScript还是脚本标签的onload事件,仅能确认脚本文件已下载完成,但reCAPTCHA Enterprise的grecaptcha对象初始化是异步进行的——此时对象可能已存在,但核心方法(比如ready)尚未挂载,导致调用时触发类型错误。

正确实现方式

通过reCAPTCHA官方提供的onload参数指定全局回调函数,确保只有当grecaptcha完全初始化后,再绑定事件和调用相关方法。同时优化Cookie同意逻辑,处理用户已同意的历史状态,避免重复加载脚本。

步骤1:定义全局初始化回调函数

// 全局函数,reCAPTCHA完全初始化后自动触发
function onRecaptchaReady() {
  const contactForm = document.getElementById("contact-form");
  const submitButton = document.getElementById("btnSubmit");
  const recaptchaResponseInput = document.getElementById("recaptcha_response");

  submitButton.addEventListener("click", function(event) {
    event.preventDefault();
    // 此时grecaptcha.ready方法已可用
    grecaptcha.ready(function () {
      grecaptcha.execute('你的站点密钥', { action: 'submit' }).then(function (token) {
          recaptchaResponseInput.value = token;
          contactForm.submit();
      });
    });
  });
}

步骤2:Cookie同意与脚本加载逻辑

document.addEventListener("DOMContentLoaded", function() {
  const cookieBanner = document.getElementById("cookie-banner");
  const acceptCookiesButton = document.getElementById("accept-cookies");
  const contactform = document.getElementById("contactform");

  // 检查用户是否已同意过Cookie
  if (localStorage.getItem("cookieConsent") === "true") {
    loadRecaptcha();
    cookieBanner.style.display = "none";
    contactform.style.display = "block";
    return;
  }

  acceptCookiesButton.addEventListener("click", function() {
    localStorage.setItem("cookieConsent", "true");
    loadRecaptcha();
    cookieBanner.style.display = "none";
    contactform.style.display = "block";
  });

  // 封装加载逻辑,避免重复加载
  function loadRecaptcha() {
    if (document.querySelector('script[src*="recaptcha/enterprise.js"]')) return;
    
    const script = document.createElement("script");
    // 通过onload参数指定全局回调,确保初始化完成
    script.src = "https://www.google.com/recaptcha/enterprise.js?render=你的站点密钥&onload=onRecaptchaReady";
    script.async = true;
    script.defer = true;
    document.body.appendChild(script);
  }
});

用户授权前阻止加载的最佳实践

  • 初始状态零加载:页面默认不引入任何reCAPTCHA相关脚本、标签或资源
  • 按需动态加载:仅在用户点击同意按钮后,才动态创建脚本标签加载库
  • 记住用户选择:通过localStorage存储同意状态,下次访问直接加载,无需重复询问
  • 避免重复加载:加载前检查是否已存在reCAPTCHA脚本,防止多次点击同意按钮导致重复请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:54:50