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

Next.js电商Stripe Checkout批量结算购物车商品问题求助

问题分析与修复方案

前端代码核心问题及修复

  1. 表单提交未阻止默认行为:点击按钮后触发表单默认提交逻辑,导致页面重载、购物车清空。
  2. 函数未实际执行:updateState和postData仅做了引用,未调用执行,且未处理异步请求的等待逻辑。
  3. JSON序列化错误:JSON.stringify传入多个参数时只会序列化第一个,需传递完整的对象结构。
  4. 冗余状态拆分:无需将购物车数据拆分为单独的id/price等数组,直接传递完整购物车数据更高效。

修改后的前端代码:

const stripePromise = loadStripe(
  process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
);

function Checkout() {
  const [basket] = useAppContext(); // 假设basket是购物车商品数组,每个商品包含id、price、description、title字段
  const { data: session } = useSession();

  const postData = async () => {  
    const response = await fetch("/api/checkout_sessions", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ basket }),
    });
    const { url } = await response.json();
    window.location.href = url;
  };
  
  React.useEffect(() => {
    const query = new URLSearchParams(window.location.search);
    if (query.get('success')) {
      console.log('订单已提交!你将收到确认邮件。');
      // 可选:结算成功后清空购物车
      // addToBasket([]);
    }

    if (query.get('canceled')) {
      console.log('订单已取消 -- 继续购物,准备好后再结算。');
    }
  }, []);

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      await postData();
    }}>
      <button 
        type="submit"
        role="link"
        className="button"
      >                       
        前往结算
      </button>
    </form>
  );
}

后端代码核心问题及修复

  1. Line Items结构错误:同时使用price和price_data(两者互斥),且未处理多商品数组的遍历生成。
  2. 参数接收错误:未正确接收前端传来的购物车数组,而是尝试提取单个字段。
  3. 金额单位错误:Stripe的unit_amount要求以分为单位,需将美元金额转换为整数分。

修改后的后端代码:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

export default async function handler(req, res) {
  if (req.method === 'POST') {
    try {
      const { basket } = req.body;
      const lineItems = basket.map(item => ({
        quantity: 1,
        price_data: { 
          currency: 'usd',
          unit_amount: Math.round(item.price * 100), // 转换为分(假设item.price是美元金额)
          product_data: {  
            description: item.description,
            name: item.title,
          }
        }
      }));

      const session = await stripe.checkout.sessions.create({
        shipping_address_collection: {
          allowed_countries: ["US", "CA", "GB"],
        },
        line_items: lineItems,
        mode: 'payment',
        success_url: `${req.headers.origin}/?success=true`,
        cancel_url: `${req.headers.origin}/?canceled=true`,
      });
      res.status(200).json({ url: session.url });
    } catch (err) {
      res.status(err.statusCode || 500).json(err.message);
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}

额外注意事项

  • 确保basket数组中的每个商品对象包含price(数字类型的美元金额)、title、description字段。
  • 如果商品已在Stripe后台创建了价格ID,可将price_data替换为price: item.stripePriceId(移除price_data),更符合Stripe最佳实践。
  • 测试时使用Stripe测试卡号(如4242 4242 4242 4242)模拟支付流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 10:35:25