You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AlpineJS调用异步reCAPTCHA报错 异步JS同步实现方法

问题原因
  • 直接报错原因:AlpineJS 的 x-on 指令默认将绑定表达式包裹在普通同步函数中执行,直接在表达式内使用 await 会触发语法错误:await is only valid in async functions and the top level bodies of modules,和截图中的报错完全一致。
  • 核心逻辑错误:现有captcha()异步函数不符合Promise异步编程规范,没有等待reCAPTCHA异步流程执行完成就提前返回。grecaptcha.ready()是异步注册回调的API,回调内给resp赋值的逻辑执行时机晚于外层函数return resp的时机,即使补充了return语句,函数返回的也永远是undefined,无法拿到run()的执行结果。
  • 业务逻辑漏洞:当前代码获取reCAPTCHA token后未传入后续请求流程,后端无法完成验证码有效性校验,reCAPTCHA防护完全不生效。
修正方案

1. 重写captcha异步函数

将reCAPTCHA的就绪等待、令牌获取逻辑全部改为await写法,确保函数等待所有异步流程完成后再返回结果,同时将令牌传入业务逻辑供后端校验:

async function captcha() {
  // 等待reCAPTCHA脚本加载就绪
  await new Promise(resolve => grecaptcha.ready(resolve));
  // 拉取当前用户的校验令牌
  const recaptchaToken = await grecaptcha.execute(recaptcha_site_key, {action: 'run'});
  console.log('reCAPTCHA verify token:', recaptchaToken);
  // 将令牌传入原有业务逻辑,后续request请求必须携带该令牌发送给后端做合法性校验
  return run(recaptchaToken);
}

同步修改run()函数,增加入参接收token,在request调用时将token提交给后端。

2. 修正Alpine事件绑定

禁止在x-on绑定的表达式中直接裸写await,选择以下任意一种写法即可:

推荐写法:抽离组件异步方法

在Alpine组件初始化逻辑中定义async类型的点击处理方法,模板直接调用该方法,逻辑更清晰易维护:

document.addEventListener('alpine:init', () => {
  Alpine.data('runActionForm', () => ({
    response: null,
    async handleRun() {
      this.response = await captcha();
    }
  }))
})

对应按钮模板修改为:

<div x-data="runActionForm">
  <button x-on:click.prevent|debounce.3s="handleRun()" type="button">Run</button>
</div>

简易写法:模板内包裹async立即执行函数

如果不想抽离组件方法,可以将异步逻辑包裹在自执行async函数中,不推荐在业务复杂场景使用,模板冗余度高:

<button x-on:click.prevent|debounce.3s="(async () => { response = await captcha() })()" type="button">Run</button>
补充说明
  • Alpine自带的debounce修饰符对async处理函数完全兼容,防抖计时从点击触发时开始计算,不会等待Promise执行完成,符合原有的3秒防抖需求。
  • 必须在后端接口层完成reCAPTCHA token的有效性校验,前端拿到的token不能作为校验通过的依据,否则防护可以被轻易绕过。

内容的提问来源于stack exchange,提问作者nskalis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 13:24:29