React集成Google reCaptcha v3遇到重复API调用及版本不匹配问题
React集成Google reCaptcha v3遇到重复API调用及版本不匹配问题
问题背景
我最近在React项目中搭配Express后端集成Google reCaptcha v3时,碰到了两个棘手的问题,先贴出我的实现代码,再具体说说问题:
前端实现代码
import { GoogleReCaptcha, GoogleReCaptchaProvider, useGoogleReCaptcha } from 'react-google-recaptcha-v3'; import axios from 'axios'; import React, { useState } from 'react'; const RECAPTCHA_SITE_KEY: string = '我已经填了生成的站点密钥'; export default function SignIn() { const { executeRecaptcha } = useGoogleReCaptcha(); const [captchaValue, setCaptchaValue] = React.useState<string | null>(null); const [error, setError] = useState<string | null>(null); // 假设存在 validateInputs、dispatch、showAlert 等函数 const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); if (!validateInputs()) return; if (!executeRecaptcha) { console.warn("reCAPTCHA not yet available"); setError('Please complete the CAPTCHA.'); return; } try { const captchaResponse = await axios.post('http://localhost:3001/api/v1/verify-captcha', { token: captchaValue, }); if (!captchaResponse.data.success) { setError('Captcha verification failed. Please try again.'); return; } // 后续登录逻辑... } catch (err) { console.error('Error during login:', err); dispatch(showAlert({ message: "Login failed. Please try again.", severity: "error" })); } }; // 这里重复定义了组件,是语法错误! export default function SignIn() { <GoogleReCaptchaProvider reCaptchaKey={RECAPTCHA_SITE_KEY}> <GoogleReCaptcha onVerify={token => { setCaptchaValue(token); }} /> </GoogleReCaptchaProvider> } }
遇到的问题
- 触发了多次重复的API调用
- 抓包发现调用的是v2的API端点(
google.com/recaptcha/api2/reload?k=我的密钥),但明明集成的是v3版本
问题分析与解决方案
看起来你遇到的问题主要是代码里的语法错误和库的使用习惯问题导致的,我来帮你一步步排查解决:
1. 组件重复定义导致逻辑混乱
你的代码里重复定义并导出了两次SignIn组件,这会直接导致React组件渲染逻辑异常,可能触发reCaptcha重复初始化,进而引发多次API调用,这是最明显的语法错误,必须先删掉重复的组件定义。
2. 错误使用GoogleReCaptcha组件引发重复验证
react-google-recaptcha-v3库中的GoogleReCaptcha组件默认会在组件挂载时自动执行reCaptcha验证,如果组件重复渲染,就会重复生成token、触发API调用。而v3的最佳实践是在表单提交时手动调用executeRecaptcha,而不是依赖自动执行的组件。
3. 版本不匹配的根源
调用v2端点的问题,大概率是因为GoogleReCaptcha组件(自动执行型)是v2的使用习惯,v3更推荐手动调用API;另外也请确认你在Google控制台生成的是v3类型的密钥,而不是v2的。
修正后的完整代码
前端代码
import React, { useState } from 'react'; import { GoogleReCaptchaProvider, useGoogleReCaptcha } from 'react-google-recaptcha-v3'; import axios from 'axios'; const RECAPTCHA_SITE_KEY: string = '你的v3站点密钥'; export default function SignIn() { const { executeRecaptcha } = useGoogleReCaptcha(); const [error, setError] = useState<string | null>(null); // 你的输入验证逻辑 const validateInputs = () => { // 示例:验证输入不为空 // return !!email && !!password; return true; }; const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); setError(null); if (!validateInputs()) return; if (!executeRecaptcha) { console.warn("reCAPTCHA 还未加载完成"); setError('请稍等,CAPTCHA正在初始化...'); return; } try { // 手动执行reCaptcha,必须指定action(v3要求,用于区分不同场景) const captchaToken = await executeRecaptcha('sign_in'); if (!captchaToken) { setError('CAPTCHA验证失败,请重试'); return; } // 发送token到后端验证 const captchaResponse = await axios.post('http://localhost:3001/api/v1/verify-captcha', { token: captchaToken, }); if (!captchaResponse.data.success) { setError('Captcha验证失败,请重试'); return; } // 验证通过,执行登录逻辑 console.log('Captcha验证通过,开始登录...'); // 你的登录请求代码... } catch (err) { console.error('登录过程出错:', err); // dispatch(showAlert({ message: "登录失败,请重试", severity: "error" })); } }; return ( <GoogleReCaptchaProvider reCaptchaKey={RECAPTCHA_SITE_KEY}> <form onSubmit={handleSubmit}> {/* 你的表单输入框,比如邮箱、密码 */} {/* <input type="email" name="email" placeholder="邮箱" /> <input type="password" name="password" placeholder="密码" /> */} {error && <div style={{ color: 'red', margin: '10px 0' }}>{error}</div>} <button type="submit">登录</button> </form> </GoogleReCaptchaProvider> ); }
后端验证代码(Express)
确保后端用的是Google官方的验证端点(v2和v3通用此端点,但v3会返回score字段用于风险判断):
const express = require('express'); const axios = require('axios'); const cors = require('cors'); const app = express(); app.use(express.json()); app.use(cors()); // 解决跨域问题 const RECAPTCHA_SECRET_KEY = '你的v3密钥'; app.post('/api/v1/verify-captcha', async (req, res) => { const { token } = req.body; try { // 调用Google的验证端点 const response = await axios.post( 'https://www.google.com/recaptcha/api/siteverify', null, { params: { secret: RECAPTCHA_SECRET_KEY, response: token, }, } ); const { success, score, action } = response.data; // v3可以根据score判断风险(一般score >= 0.5为正常请求) if (success && action === 'sign_in' && score >= 0.5) { return res.json({ success: true }); } else { return res.json({ success: false, message: 'Captcha验证不通过,可能是机器人请求' }); } } catch (err) { console.error('Captcha验证出错:', err); return res.status(500).json({ success: false, message: '服务器内部错误' }); } }); app.listen(3001, () => console.log('后端服务运行在3001端口'));
额外注意事项
- 确保Google控制台的密钥是v3类型:登录Google reCaptcha控制台,检查你的密钥对应的版本是v3。
- 更新依赖:执行
npm update react-google-recaptcha-v3确保使用最新版本的库。 - 跨域问题:如果前端和后端域名不同,一定要在Express中配置CORS(上面的后端代码已经加了)。
备注:内容来源于stack exchange,提问作者Akshat Parashar
相关产品推荐
相关产品推荐

