Rails中仅页面跳转时出现ReCAPTCHA BROWSER_ERROR问题
Rails Turbo跳转后Google ReCAPTCHA Enterprise出现BROWSER_ERROR的解决方案
问题场景
Rails应用集成Google ReCAPTCHA Enterprise后,直接刷新页面提交表单完全正常;但通过Turbo驱动的link_to跳转至表单页面时,后端调用create_assessment会返回token_properties.valid为false,且invalid_reason为:BROWSER_ERROR。
核心原因
Turbo采用局部页面更新机制,不会重新加载整个页面的JavaScript执行上下文。ReCAPTCHA Enterprise的初始化依赖页面首次加载时的全局环境绑定,Turbo跳转后,原有的grecaptcha实例状态失效,导致生成的token无法通过谷歌的验证逻辑。
解决方案
通过监听Turbo的turbo:load事件,在每次页面加载(包括Turbo跳转)时重置ReCAPTCHA状态,并确保表单提交事件正确绑定到新DOM元素:
1. 前端代码调整
修改ReCAPTCHA相关的JavaScript逻辑,添加Turbo事件监听和状态重置:
document.addEventListener('turbo:load', () => { // 绑定表单提交事件(事件委托适配Turbo动态渲染的表单) document.addEventListener('submit', async (event) => { const form = event.target; // 仅处理标记了ReCAPTCHA动作的表单(给表单添加data-recaptcha-action属性) if (form.hasAttribute('data-recaptcha-action') && !form.querySelector('[name=recaptcha]')) { event.preventDefault(); const action = form.getAttribute('data-recaptcha-action'); try { const recaptchaData = await recaptcha(action); const input = document.createElement('input'); input.setAttribute('name', 'recaptcha'); input.setAttribute('value', JSON.stringify(recaptchaData)); input.classList.add('d-none'); form.appendChild(input); form.querySelector('[type=submit]').click(); } catch (error) { console.error('ReCAPTCHA token获取失败:', error); // 可在此添加用户可见的错误提示 } } }); // 重置或重新初始化ReCAPTCHA Enterprise if (typeof grecaptcha !== 'undefined' && grecaptcha.enterprise) { // 重置现有实例状态,适配Turbo跳转后的环境 grecaptcha.enterprise.reset(); } else { // 若ReCAPTCHA脚本未加载,动态注入脚本 const siteKeyElement = document.getElementById('recaptcha-site-key'); if (siteKeyElement) { const siteKey = siteKeyElement.textContent; const script = document.createElement('script'); script.src = `https://www.google.com/recaptcha/enterprise.js?render=${siteKey}`; script.async = true; script.defer = true; document.body.appendChild(script); } } }); export function recaptcha(action) { return new Promise((resolve, reject) => { // 确保grecaptcha ready后再执行 grecaptcha.enterprise.ready(async () => { try { const token = await grecaptcha.enterprise.execute( document.getElementById('recaptcha-site-key').textContent, { action } ); resolve({ token, action }); } catch (error) { reject(error); } }); }); }
2. 表单标记调整
在需要ReCAPTCHA的表单上添加data-recaptcha-action属性,指定对应的动作名称:
<%= form_with(model: @model, html: { 'data-recaptcha-action': 'submit_form' }) do |form| %> <!-- 表单内容 --> <%= form.submit '提交' %> <% end %>
3. 后端代码确认
你的后端创建评估的代码无需修改,但需确保:
site_key和project_id配置正确,与谷歌控制台一致- 从前端接收的
recaptcha参数正确解析为token和action
验证步骤
- 通过Turbo链接跳转到表单页面
- 提交表单,检查后端是否能成功创建评估,无
:BROWSER_ERROR - 多次跳转后重复验证,确保状态稳定
内容的提问来源于stack exchange,提问作者Jon McClung
相关产品推荐
相关产品推荐

