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

为什么.map()首次输出数组正常,第二次返回undefined致Stripe报错?

问题描述

开发Next.js对接Stripe支付的API接口时遇到以下问题:

  • 执行bodyItems?.map()生成renderCartItems数组时,首次能输出符合Stripe要求的结构,第二次执行返回undefined
  • 第二次请求触发Stripe报错:The line_items parameter is required in payment mode.
  • 接口会被执行两次,开启React严格模式后该现象仍存在

控制台日志输出:

[
  {
    name: 'sped',
    qty: 1,
    price: 5000,
    img: { _type: 'image', asset: [Object] },
    ogprice: 5000
  }
]
[
  {
    price_data: { currency: 'usd', product_data: [Object], unit_amount: 5000 },
    quantity: 1
  }
] mapped

undefined
undefined mapped

相关API路由代码:

export default async function handler(req, res) {
    if (req.method === 'POST') {
        try {
            const bodyItems = req.body.items;
            console.log(bodyItems)
            
            const renderCartItems = bodyItems?.map( singleProduct => {
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: singleProduct.name
                        },
                        unit_amount: singleProduct.price
                    },
                    quantity: singleProduct.qty,
                }
            })
            console.log(renderCartItems, "mapped")
            
            // Create Checkout Sessions from body params.
            const session = await stripe.checkout.sessions.create({
                line_items: renderCartItems,
                
                mode: 'payment',
                success_url: `http://localhost:3000/done`,
                cancel_url: `http://localhost:3000`,
            });
            console.log(session.url)
            res.redirect(303, session.url); 
        } catch (err) {
            res.status(err.statusCode || 500).json(err.message);
        }
    } else {
        res.setHeader('Allow', 'POST');
        res.status(405).end('Method Not Allowed');
    }
}
解决方案

1. 排查前端重复请求来源

接口被调用两次的核心原因大概率在前端:

  • 检查提交按钮是否未做防抖处理,导致重复点击触发请求
  • 确认表单提交是否同时触发默认行为和自定义请求(未执行event.preventDefault()阻止默认提交)
  • 排查组件渲染逻辑,是否因状态频繁变化导致重复发起POST请求

2. 给API接口加请求合法性校验

在处理Stripe会话创建前,先校验请求体的有效性,直接拦截无效请求:

export default async function handler(req, res) {
    if (req.method === 'POST') {
        try {
            const bodyItems = req.body.items;
            console.log(bodyItems)
            
            // 新增校验:确保items存在且为非空数组
            if (!bodyItems || !Array.isArray(bodyItems) || bodyItems.length === 0) {
                return res.status(400).json({ error: "请求体中缺少有效商品列表" });
            }
            
            const renderCartItems = bodyItems.map( singleProduct => {
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: singleProduct.name
                        },
                        unit_amount: singleProduct.price
                    },
                    quantity: singleProduct.qty,
                }
            })
            console.log(renderCartItems, "mapped")
            
            const session = await stripe.checkout.sessions.create({
                line_items: renderCartItems,
                mode: 'payment',
                success_url: `http://localhost:3000/done`,
                cancel_url: `http://localhost:3000`,
            });
            console.log(session.url)
            res.redirect(303, session.url); 
        } catch (err) {
            res.status(err.statusCode || 500).json(err.message);
        }
    } else {
        res.setHeader('Allow', 'POST');
        res.status(405).end('Method Not Allowed');
    }
}

3. 给renderCartItems加空值兜底

即使校验环节遗漏,通过兜底避免传递undefined给Stripe:

const renderCartItems = (bodyItems?.map(singleProduct => ({
    price_data: {
        currency: 'usd',
        product_data: { name: singleProduct.name },
        unit_amount: singleProduct.price
    },
    quantity: singleProduct.qty,
}))) || [];

4. 临时关闭React严格模式辅助排查

开发环境下React严格模式会重复执行组件的某些生命周期,可能间接引发重复请求。可以临时关闭next.config.js或app/layout.js中的严格模式,确认是否是严格模式触发的前端重复渲染导致的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 17:20:28