React使用Recaptcha3验证表单对接Firebase Functions出现token未定义及超时问题
问题原因与修复方案
一、初始token为undefined的问题
- 取值对象错误:请求参数存放在
req(请求对象)而非res(响应对象)上,你写的res.query.body完全错误 - 字段名不匹配:前端通过GET查询参数传递的是
token字段,不是body字段,正确写法是const token = req.query.token - 拼写错误:配置读取语句
functions.config().recaptacha.key中多了一个字母a,若你的Firebase配置命名为recaptcha,此处需修正为functions.config().recaptcha.key
二、后续函数超时的问题
核心原因是HTTP类型的Firebase云函数必须主动返回响应给客户端,否则函数会一直挂起直到达到默认60秒的超时阈值。你当前的代码无论验证成功还是失败,都没有返回任何响应给前端,必然触发超时。同时catch块直接抛出错误不会被前端接收,需要通过响应对象手动返回错误信息。
修正后的云函数代码
const axios = require('axios') const USER_ERROR_CODES = ['missing-input-response', 'invalid-input-response'] exports.sendRecaptcha = functions.https.onRequest(async (req, res) => { res.set('Access-Control-Allow-Origin', '*') res.set('Access-Control-Allow-Methods', 'GET, PUT, POST, OPTIONS') res.set('Access-Control-Allow-Headers', '*') // 处理跨域预检请求 if (req.method === 'OPTIONS') { return res.status(204).send('') } try { const secret = functions.config().recaptcha.key; functions.logger.log("SECRET:", secret); const token = req.query.token; functions.logger.log("token", token); // 提前校验token是否存在 if (!token) { return res.status(400).json({success: false, error: 'missing token'}) } let result = await axios({ method: 'post', url: 'https://www.google.com/recaptcha/api/siteverify', params: { secret: secret, response: token, } }); let data = result.data || {}; if(!data.success){ return res.status(400).json({ success: false, error: 'response not valid' }) } // 验证成功返回结果给前端 return res.status(200).json({success: true, score: data.score}) } catch(err){ console.log(err); const errorRes = err.response ? err.response.data : {success: false, error: 'captcha_error'} return res.status(500).json(errorRes) } })
可选优化建议
- 把前端GET请求改为POST请求传递token,GET参数会留存到请求日志中,安全性更低
- 生产环境将跨域允许源
*替换为你自己的前端域名,降低安全风险 - 验证通过后增加score阈值判断,reCAPTCHA v3得分低于0.5可直接判定为机器操作,拒绝表单提交
内容的提问来源于stack exchange,提问作者Trond Kristiansen
相关产品推荐
相关产品推荐

