用户授权后加载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
相关产品推荐
相关产品推荐

