调用Google reCAPTCHA v2 siteverify API返回异常数据问题排查
我开发了一个带注册/登录页面的Vue-Express应用,在两个页面里都用了Google reCAPTCHA v2的隐形验证模式,手动调用execute函数拿到了如下有效token:
03AEkXODA0y6WEjvR8wd507P9Bnmm63hcOP2gMGJBsuN7PFpFJbeGE3r2M-3btinH4xMIu3OeFnpmLwrwJvlhPbyX7dkCzD_3jnbytUr7wrLC0X55O7qO3wrlF94H2ydekNYPutxvj-XaRKWcq_Dw96B5zSuc7h0xqqJgbao54jqHEB3RC5C0MWPkI6tf44TydsUscwlas9lKHG5tQZYNkOdtVwael4SUJuCvs6A5EADsKnUUKHOvfMX1a3-BUDC3fy1bRmqc7uGrmu-_6UUxNN10-7jR_9Cu9AZq94DGQ8YTnN0OJ0Jl_3w5ehl1HToAkW-RX4xWZsJlprccUm8P2Pk30W_KVGrm7W-N_z9w0c-MdFZfH7qV1xkf_hHO6hidvf_WYB_Sw8fBujV8PihixKSH6DKtsn3rVX4tA9BuyxVTTse4g1skqmpxF4Lp3CjAtzRJWwbtKLYCNHy0cTyIZ2AAR1v9QLMY4Mlz5DXIuFb4YTecvsjlxTG6F09gGjMWrWiQ4H-6q7BfE
之后把这个token传给Express后端,调用Google的验证API:
https://www.google.com/recaptcha/api/siteverify?secret=<recaptcha_secret_key>&response=<token>
此时后端得到异常响应(见截图),但用Postman发送完全相同的请求时,返回结果是:
{ "success": false, "error-codes": [ "timeout-or-duplicate" ] }
我搞不清问题出在哪,求解决思路。
更新:获取token的代码逻辑
点击登录按钮时会调用onCaptchaVerified方法,同时该方法也会被验证码组件携带有效token再次触发,代码如下:
Vue组件中的验证码标签:
<vue-recaptcha ref="recaptcha" size="invisible" verify="onCaptchaVerified" expired="onCaptchaExpired" sitekey="sitekey" />
对应的方法实现:
async onCaptchaVerified(token) { await this.$refs.recaptcha.execute() if(!token) { return false } console.log("logging in...", token); const res = await postRequest('validate-human', { token: token }) console.log(res.data.data) }
问题分析与解决建议
重复调用execute导致token失效
隐形reCAPTCHA的verify回调本身就是验证成功后返回有效token的,你在回调里又调用了execute(),会再次触发验证生成新token,或者把当前token标记为已使用。当你用回调里的旧token去验证时,就会返回timeout-or-duplicate错误。
解决:把execute()移到登录按钮的点击方法里,回调只处理token提交:// 登录按钮点击事件 async handleLogin() { await this.$refs.recaptcha.execute() } // 验证成功回调 async onCaptchaVerified(token) { if(!token) return false console.log("logging in...", token); const res = await postRequest('validate-human', { token }) console.log(res.data.data) }组件绑定方式错误
Vue中绑定事件应该用@前缀,你写的verify="onCaptchaVerified"会被当作字符串,可能导致回调触发异常。修正组件标签:<vue-recaptcha ref="recaptcha" size="invisible" @verify="onCaptchaVerified" @expired="onCaptchaExpired" :sitekey="sitekey" />后端请求方式问题
Google推荐用POST请求调用siteverify API,GET方式可能因token过长导致URL截断,引发异常。后端改成POST请求:// Express后端示例 const axios = require('axios'); app.post('/validate-human', async (req, res) => { const { token } = req.body; const secretKey = '你的secret key'; try { const response = await axios.post('https://www.google.com/recaptcha/api/siteverify', null, { params: { secret: secretKey, response: token, remoteip: req.ip // 可选,添加客户端IP提升验证准确性 } }); res.json(response.data); } catch (error) { res.status(500).json({ success: false, error: '验证请求失败' }); } });防止重复提交
检查是否存在按钮重复点击导致多次提交同一token的情况,添加按钮防抖或禁用逻辑,避免触发重复验证。
内容的提问来源于stack exchange,提问作者Rahul Mehta

