SvelteKit联系表单中ReCAPTCHA Token获取后传递丢失问题的解决方法
问题分析与解决思路
兄弟,你的问题核心是异步操作处理不当!getCaptcha里的grecaptcha.execute是异步执行的,但你现在用同步方式获取返回值,自然会拿到null——因为函数还没等异步请求完成就已经返回了。
为什么会出现这个问题?
你看,grecaptcha.ready和.then都是异步回调,当你执行let token = getCaptcha()时,getCaptcha函数并没有等待异步操作完成就提前返回了(而且原函数里也没返回任何异步对象),所以token必然是undefined。
修复步骤
1. 把getCaptcha改成返回Promise的异步函数
我们需要让这个函数等待ReCAPTCHA的token生成完成后再返回结果:
async function getCaptcha(): Promise<string> { // 先等待grecaptcha初始化完成 await new Promise(resolve => grecaptcha.ready(resolve)); // 执行获取token的操作并返回 const token = await grecaptcha.execute('recaptcha-key', { action: 'contactForm' }); console.log(token); // 这里依然能正常打印token return token; }
或者用传统Promise写法也可以:
function getCaptcha(): Promise<string> { return new Promise((resolve) => { grecaptcha.ready(function () { grecaptcha.execute('recaptcha-key', { action: 'contactForm' }) .then(function (token) { console.log(token); resolve(token); }); }); }); }
2. 修改sendMail函数,用await等待token返回
因为调用了异步函数,sendMail也要改成异步函数,确保拿到token后再组装FormData:
const sendMail = async (values) => { const url = '/sendmail.php'; const formData = new FormData(); try { // 等待token获取完成 let token = await getCaptcha(); console.log('token: ' + token); // 现在能拿到正确的token了 // 把token和表单字段都加入FormData formData.append("token", token); // 这里记得把values里的其他表单字段也加进去(比如姓名、邮箱、消息内容) Object.entries(values).forEach(([key, value]) => { formData.append(key, value); }); // 发送请求 const response = await fetch(url, { method: 'post', body: formData, }); console.debug(response.status); // 这里可以添加提交成功后的逻辑(比如提示用户) } catch (e) { sendError = true; console.debug(e); } };
额外注意事项
- 确保页面已经正确加载了ReCAPTCHA的脚本,不然
grecaptcha对象会不存在导致报错。 - 后端的
sendmail.php一定要记得验证这个token!调用Google的ReCAPTCHA验证接口(https://www.google.com/recaptcha/api/siteverify),不要只接收token就直接发送邮件,不然ReCAPTCHA的防护就形同虚设了。 - 如果是通过表单提交触发
sendMail,记得在提交事件里阻止默认行为(event.preventDefault()),避免页面刷新打断异步操作。
内容的提问来源于stack exchange,提问作者Farid
相关产品推荐
相关产品推荐

