ReactJS集成reCaptcha Enterprise报grecaptcha.enterprise.render不存在错误
问题根因
enterprise.js的load事件仅代表脚本本身的基础代码加载完成,但其内部的enterprise模块是异步懒加载的,所以触发load回调时window.grecaptcha.enterprise还未完成初始化,自然不存在render方法。
解决方案
方案1:使用官方指定的onload回调(推荐)
Google reCaptcha官方支持在脚本地址中添加onload参数,指定一个全局回调函数名,这个回调会在reCaptcha所有模块(包括enterprise)完全初始化完成后才触发,修改后代码如下:
useEffect(() => { // 定义全局回调名,避免和其他全局变量冲突 const RECAPTCHA_ONLOAD_CALLBACK = 'onReCaptchaEnterpriseReady' const containerId = "reCaptcha_Enterprise_element" let isMounted = true const initReCaptcha = () => { if (!isMounted || !window.grecaptcha?.enterprise?.render) return window.grecaptcha.enterprise.render(containerId, { sitekey: "<your-enterprise-sitekey>", }); setCaptchaLoaded(true); } const loadRecaptcha = () => { const existingScript = document.getElementById("reCaptchaEnterprise"); if (existingScript) { // 脚本已存在时直接检查是否已经初始化完成 if (window.grecaptcha?.enterprise?.render) { initReCaptcha() } else { // 还在初始化的话把当前回调挂到全局上等触发 window[RECAPTCHA_ONLOAD_CALLBACK] = initReCaptcha } return } // 挂载全局回调 window[RECAPTCHA_ONLOAD_CALLBACK] = initReCaptcha const script = document.createElement("script"); // 地址加上onload参数 script.src = `https://www.google.com/recaptcha/enterprise.js?render=explicit&onload=${RECAPTCHA_ONLOAD_CALLBACK}`; script.id = "reCaptchaEnterprise"; script.async = true; script.defer = true; document.body.appendChild(script); }; loadRecaptcha() // 清理副作用,避免组件卸载后执行逻辑 return () => { isMounted = false delete window[RECAPTCHA_ONLOAD_CALLBACK] } }, []);
方案2:轮询检测初始化状态(适合不想用全局回调的场景)
如果不想挂载全局变量,可以用短间隔轮询检测grecaptcha.enterprise.render是否存在,加上超时避免异常情况无限轮询:
useEffect(() => { const containerId = "reCaptcha_Enterprise_element" let isMounted = true let pollTimer = null const initReCaptcha = () => { window.grecaptcha.enterprise.render(containerId, { sitekey: "<your-enterprise-sitekey>", }); setCaptchaLoaded(true); } // 轮询检测 const waitForReCaptchaReady = (retryCount = 0) => { if (retryCount > 30) { // 最多轮询30次,每次100ms,总超时3s console.error('reCaptcha Enterprise加载超时') return } if (window.grecaptcha?.enterprise?.render) { initReCaptcha() return } pollTimer = setTimeout(() => waitForReCaptchaReady(retryCount + 1), 100) } const loadRecaptcha = () => { const existingScript = document.getElementById("reCaptchaEnterprise"); if (existingScript) { waitForReCaptchaReady() return } const script = document.createElement("script"); script.src = "https://www.google.com/recaptcha/enterprise.js?render=explicit"; script.id = "reCaptchaEnterprise"; script.async = true; script.defer = true; script.addEventListener("load", () => { waitForReCaptchaReady() }); document.body.appendChild(script); }; loadRecaptcha() return () => { isMounted = false clearTimeout(pollTimer) } }, []);
注意事项
- 确保你使用的sitekey是reCaptcha Enterprise版本的,普通reCaptcha v2/v3的sitekey无法在enterprise版本的sdk中使用
- 确保页面上存在id为
reCaptcha_Enterprise_element的DOM容器,否则render方法也会报错
内容的提问来源于stack exchange,提问作者Rajeev
相关产品推荐
相关产品推荐

