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

Next.js 8升级至11后使用next/script加载Google reCAPTCHA失效问题排查

Next.js 11 next/script 加载第三方脚本(reCAPTCHA、Moengage)失败的解决方案

我最近帮好几个开发者处理过Next.js从旧版本升级到11后,用next/script加载第三方脚本踩的坑,你遇到的reCAPTCHA和Moengage加载失败的情况,其实核心问题都是next/script的加载策略和传统script标签的执行时机、全局变量暴露逻辑不一样导致的。下面给你针对性的解决方案:

一、解决 reCAPTCHA 无法加载的问题

你用strategy="beforeInteractive"时,onloadCallback这个全局回调大概率还没被注册——因为beforeInteractive脚本是在Next.js核心代码加载前执行的,而你的回调函数通常是在组件或客户端代码里定义的,这时候根本不存在。

方案1:提前注册全局回调(适合全局使用reCAPTCHA的场景)

把onloadCallback定义在_document.js的<Head>里,用同步脚本提前注册,再加载reCAPTCHA:

// pages/_document.js
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'

export default function Document() {
  return (
    <Html>
      <Head>
        {/* 提前注册全局回调函数 */}
        <Script strategy="beforeInteractive" id="recaptcha-init">
          {`
            window.onloadCallback = function() {
              // 这里根据你的react-recaptcha需求初始化
              if (window.grecaptcha) {
                // 比如渲染指定元素的验证码
                window.grecaptcha.render('recaptcha-container', {
                  sitekey: '你的站点密钥',
                  callback: (response) => {
                    // 处理验证成功后的逻辑
                  }
                });
              }
            }
          `}
        </Script>
        {/* 加载reCAPTCHA脚本,此时回调已存在 */}
        <Script 
          strategy="beforeInteractive" 
          src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit"
        />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  )
}

方案2:组件内按需加载(适合局部使用reCAPTCHA的场景)

如果只在某个组件里用reCAPTCHA,改用afterInteractive策略,配合onLoad回调手动初始化,不用依赖全局onload参数:

import Script from 'next/script'
import { useEffect, useRef } from 'react'

export default function RecaptchaComponent() {
  const captchaRef = useRef(null)

  useEffect(() => {
    const initCaptcha = () => {
      if (window.grecaptcha) {
        window.grecaptcha.render(captchaRef.current, {
          sitekey: '你的站点密钥',
          // 其他配置项
        })
      }
    }

    // 脚本已加载则直接初始化,否则监听加载完成事件
    if (window.grecaptcha) {
      initCaptcha()
    } else {
      document.addEventListener('captchaLoaded', initCaptcha)
    }

    return () => document.removeEventListener('captchaLoaded', initCaptcha)
  }, [])

  return (
    <>
      <div ref={captchaRef} id="recaptcha-container" />
      <Script 
        strategy="afterInteractive" 
        src="https://www.google.com/recaptcha/api.js"
        onLoad={() => document.dispatchEvent(new Event('captchaLoaded'))}
      />
    </>
  )
}

二、解决 Moengage 无法加载的问题

Moengage依赖全局window.moengage变量,next/script的加载策略可能导致初始化代码访问不到这个变量。推荐用以下方式处理:

方案:脚本加载完成后再初始化

在使用Moengage的页面或组件中,用lazyOnload(或afterInteractive)加载脚本,然后在onLoad回调里执行初始化:

import Script from 'next/script'

export default function HomePage() {
  return (
    <>
      {/* 页面内容 */}
      <Script 
        strategy="lazyOnload"
        src="https://cdn.moengage.com/webpush/moe_webSdk.min.latest.js"
        onLoad={() => {
          if (window.moengage) {
            window.moengage = moengage.initialize({
                app_id: '你的Moengage App ID',
                // 其他配置参数
            });
          }
        }}
      />
    </>
  )
}

如果需要Moengage更早启动,把strategy换成afterInteractive即可,核心是确保初始化代码在脚本加载完成后执行。

三、给 Razor Pay 测试的建议

测试Razor Pay时,可以参考上面的思路:

  1. 先用afterInteractive或lazyOnload加载它的脚本;
  2. 在onLoad回调里执行初始化逻辑,避免直接依赖全局变量未定义的情况;
  3. 如果遇到问题,检查是否有全局回调需要提前注册,或者是否需要调整加载策略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 07:02:48