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

Next.js 13.4.1集成Paddle.js调用checkout.open时出现CORS错误

Next.js 13.4.1集成Paddle.js调用checkout.open时出现CORS错误

看起来你遇到的CORS错误其实是请求路径错误导致404的次生问题——先看报错里的请求URL,product/undefined这部分说明Paddle在生成结账请求时,没有拿到有效的价格ID,导致请求了一个不存在的资源,而Paddle的404响应没有携带跨域允许的头,才触发了浏览器的CORS报错。咱们一步步来排查解决:

第一步:先确认price_id的有效性

你调用openCheckout(offer.price_id)时,offer.price_id可能是undefined或者无效值,这是核心问题。先在代码里加日志验证:

const openCheckout = (price_id: string) => {
  console.log("当前传入的price_id:", price_id);
  if (!price_id) {
    console.error("price_id为空或未定义!");
    return;
  }
  paddle.Checkout.open({
    settings: {
      theme: 'dark'
    },
    items: [
      {
        price_id,
        quantity: 1
      }
    ]
  })
}

检查控制台输出:

  • 要确保price_id是Paddle沙箱后台生成的有效格式(比如pri_xxxxxxxxxxxx)
  • 沙箱环境的price_id和生产环境不通用,别搞混了

第二步:确保Paddle完全初始化后再调用结账

Next.js的Script组件加载是异步的,可能存在你点击按钮时Paddle还没完成初始化的情况。可以给Provider加个加载状态,避免提前调用:
修改PaddleProvider:

'use client'
import { createContext, useState } from 'react'
import Script from 'next/script'
import { getNodeEnv } from '@/utils/getNodeEnv'
import { vendor_id } from '@/helpers/APIs/paddle/config'

type PaddleContext = {
  paddle: any | null;
  isLoaded: boolean;
}

const PaddleContext = createContext<PaddleContext>({ paddle: null, isLoaded: false })

type Props = {
  children: React.ReactNode
}

const PaddleProvider: React.FC<Props> = ({ children }) => {
  const [paddle, setPaddle] = useState<any>(null)
  const [isLoaded, setIsLoaded] = useState(false)

  const initializePaddle = () => {
    if (getNodeEnv() !== 'prod') Paddle.Environment.set("sandbox")
    Paddle.Setup({
      vendor: Number(vendor_id),
    })
    setPaddle(Paddle)
    setIsLoaded(true)
  }

  return (
    <PaddleContext.Provider value={{ paddle, isLoaded }}>
      <Script
        src="https://cdn.paddle.com/paddle/paddle.js"
        onLoad={initializePaddle}
      />
      { children }
    </PaddleContext.Provider>
  )
}

export { PaddleProvider, PaddleContext }

然后在OfferOption组件里,只有加载完成才渲染可点击的按钮:

const OfferOption: React.FC<Props> = ({ offer }) => {
  const { paddle, isLoaded } = usePaddleContext()

  const openCheckout = (price_id: string) => {
    if (!price_id || !paddle) return;
    paddle.Checkout.open({
      settings: {
        theme: 'dark'
      },
      items: [
        {
          price_id,
          quantity: 1
        }
      ]
    })
  }

  if (!isLoaded) {
    return <button disabled>加载中...</button>;
  }

  return (
    <button
      type='button'
      onClick={() => openCheckout(offer.price_id)}
      {/* 其他样式属性 */}
    >
      打开结账页面
    </button>
  )
}

第三步:验证vendor_id和环境匹配

确认vendor_id是沙箱环境的ID——登录Paddle沙箱后台查看你的vendor ID,别用生产环境的ID在沙箱里测试,否则也会出现资源找不到的问题。

关于你问的几个额外问题:

  • 要不要给Next.js加请求头? 不需要,因为请求是Paddle的脚本发起的,不是你的Next.js服务器发起的,配置Next.js的CORS头对这个场景没用。
  • 代理有用吗? 没用,同样因为请求不是你的前端或服务器发起的,代理解决不了Paddle内部请求的问题。

只要解决了price_id无效或Paddle未初始化完成的问题,那个CORS报错会自动消失——毕竟它只是404带来的附属问题。

备注:内容来源于stack exchange,提问作者kroflic

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.21 15:12:58