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

Next.js API传参至Stripe报错:缺少line_items必填名称参数

问题分析与修复方案

你的代码存在几个关键问题,导致Stripe提示缺少必填参数,下面逐一拆解并修复:

前端代码的核心问题

1. 状态更新逻辑错误

  • 遍历basket时,错误使用basket.title,应该用当前遍历项element.title;
  • React的setState是异步批量更新的,在forEach循环中多次调用会导致状态无法正确累加,应该先收集所有商品数据再一次性更新状态。

2. JSON序列化参数错误

JSON.stringify(id, price, description, title) 只会序列化第一个参数id,后端根本接收不到price、description、title这些数据。正确做法是把所有数据包装成一个对象再序列化。

3. 事件触发与表单冲突

  • 按钮的onClick里只是引用了函数,没有执行(缺少());
  • 表单的默认POST提交会刷新页面,和手动调用的fetch冲突,需要阻止默认行为。

修正后的前端代码

import { useState } from 'react';

export default function CheckoutButton({ basket }) {
  // 无需单独存每个字段的state,直接在请求时处理basket数据
  const handleCheckout = async (e) => {
    e.preventDefault(); // 阻止表单默认提交行为
    
    // 从basket整理Stripe需要的商品数据
    const itemsData = basket.map(element => ({
      title: element.title,
      description: element.description,
      price: element.price
    }));

    try {
      const response = await fetch("/api/checkout_sessions", {
        method: "POST",
        headers: {
          'Content-Type': 'application/json', // 指定Content-Type,确保后端能解析JSON
        },
        body: JSON.stringify({ items: itemsData }),
      });
      const data = await response.json();
      if (response.ok) {
        window.location.href = data.url; // 跳转到Stripe结账页面
      } else {
        console.error('结账请求失败:', data.message);
      }
    } catch (err) {
      console.error('网络请求失败:', err);
    }
  };

  return (
    <form onSubmit={handleCheckout}>
      <button type="submit" className="button">
        proceed to checkout
      </button>
    </form>
  );
}

API端代码的核心问题

1. 数据接收与line_items生成错误

  • 前端传递的是多商品数组,你只生成了一个line_item;
  • 直接使用req.body.title会拿到数组,而Stripe要求product_data.name是字符串;
  • unit_amount需要转换为分(比如10美元要传1000),否则金额会异常。

修正后的API代码

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

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { items } = req.body;
    
    // 验证商品数据是否有效
    if (!items || items.length === 0) {
      return res.status(400).json({ message: '未提供商品数据' });
    }

    try {
      // 为每个商品生成对应的line_item
      const lineItems = items.map(item => ({
        price_data: { 
          unit_amount: Math.round(item.price * 100), // 转换为分
          currency: 'usd',
          product_data: {  
            name: item.title,
            description: item.description,
          },
        },
        quantity: 1,
      }));

      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 }); // 返回结账URL给前端跳转
    } catch (err) {
      res.status(err.statusCode || 500).json({ message: err.message });
    }
  } else {
    res.setHeader('Allow', 'POST');
    res.status(405).end('Method Not Allowed');
  }
}

额外说明

  • 不再需要单独维护id、price等状态,直接从basket提取数据更高效,也避免了异步状态更新的问题;
  • 前端通过window.location.href跳转到Stripe结账页面,替代后端重定向,更符合Next.js前后端分离的逻辑;
  • 增加了数据验证和错误捕获,便于排查问题。

内容的提问来源于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 13:31:00