尝试使用打字稿在 MERN 堆栈应用程序中以编程方式实现 reCAPTCHA,我收到错误
recaptchaUtils.ts:9 reCAPTCHA error: Error: Invalid listener argument
at recaptcha__en.js:108:394
at H2 (recaptcha__en.js:609:438)
at Object.ready (recaptcha__en.js:389:417)
at executeRecaptcha (recaptchaUtils.ts:6:1)
at AuthContext.tsx:112:1
at new Promise (<anonymous>)
at login (AuthContext.tsx:110:1)
at handleLogin (Login.tsx:51:1)
at onKeyDown (Login.tsx:102:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
当我尝试调用此函数时:
// utils/recaptchaUtils.ts
declare const grecaptcha: any;
export const executeRecaptcha = async (action = 'submit') => {
if (!grecaptcha || !process.env.REACT_APP_RECAPTCHA_SITE_KEY) {
console.error("reCAPTCHA library or site key not available");
return;
}
try {
await grecaptcha.ready();
return await grecaptcha.execute(process.env.REACT_APP_RECAPTCHA_SITE_KEY, { action });
} catch (error) {
console.error("reCAPTCHA error:", error);
}
};
正如你所看到的,它到达了try-catch块,但是没有成功执行。
我想到了两个潜在的问题,比如站点密钥不正确(我已经仔细检查过在开发版本和构建版本中都正确),第二个问题是竞争条件。
但是,我确信 reCAPTCHA 是在调用我的
executeRecaptcha
函数之前加载的,因为它是这样加载的:
// App.tsx
// ...
declare const grecaptcha: any;
function App() {
useEffect(() => {
const script = document.createElement('script');
script.src = `https://www.google.com/recaptcha/api.js?render=${process.env.REACT_APP_RECAPTCHA_SITE_KEY}`;
script.async = true;
script.defer = true;
script.onload = () => {
console.log('reCAPTCHA library loaded.');
grecaptcha.ready(() => {
console.log('reCAPTCHA is ready.');
});
};
document.head.appendChild(script);
return () => {
document.head.removeChild(script);
};
}, []);
// ...
我成功地在控制台中看到了
reCAPTCHA library loaded.
和 reCAPTCHA is ready.
。
我尝试在index.js头中包含reCAPTCHA,但结果相同。
我尝试不使用
await
,但结果相同。
我尝试不卸载 reCAPTCHA 脚本,但结果相同。
我尝试在开发和生产环境中进行测试,但结果相同。
我尝试从不同的组件调用
executeRecaptcha()
,但结果相同。
我尝试阅读 reCAPTCHA 文档,但没有找到任何有用的东西。
我已通过将
executeRecaptcha
函数更改为 来修复错误
export const executeRecaptcha = async (action = 'submit'): Promise<string> => {
return new Promise<string>((resolve, reject) => {
grecaptcha.ready(() => {
try {
grecaptcha.execute(process.env.REACT_APP_RECAPTCHA_SITE_KEY, { action })
.then((token: string) => {
resolve(token);
})
.catch((error: any) => {
console.error("reCAPTCHA error:", error);
reject(error);
});
} catch (error) {
console.error("reCAPTCHA error:", error);
reject(error);
}
});
});
};
我能够使用这种方法在精简的应用程序上解决这个问题。显然 async/await 不是这里适用的模式。还要注意在 html 中包含 recaptcha 脚本。我希望它有帮助。
function validateCaptcha(): Promise<string> {
return new Promise((resolve, reject) => {
grecaptcha.ready(() => {
grecaptcha.execute('XXXX', {action: 'submit'})
.then(token => {
resolve(token);
})
.catch(error => {
console.error("Error executing reCAPTCHA", error);
reject(error);
});
});
});
}