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

Stripe集成问题:支付成功后如何自动移除用户购物车商品?

如何在Stripe支付成功后才清空用户购物车?

我已经在电商网站里集成了Stripe API,结账时用户会跳转到Stripe的支付链接填写信息,支付可能成功也可能取消。目前所有功能都正常,但我需要实现只有在支付成功时才移除用户的全部购物车商品。

我尝试了以下方法均未成功:

  • 直接在创建checkout session后调用cartItem.remove({ user: req.body.user }),但不管支付成功与否都会清空购物车;
  • 通过判断session的payment_status字段,但创建session时这个状态是unpaid,没法在支付成功后触发判断;
  • 考虑用success_url结合React的useEffect调用移除购物车接口,但这个方案不够优雅。

原创建Checkout Session代码

app.post('/api/createCheckoutSession', async (req, res) => {
    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }
            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,
        })

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }
});

尝试直接移除购物车的代码

app.post('/api/createCheckoutSession', async (req, res) => {
    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }
            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,
        })

        cartItem.remove({ user: req.body.user }, function (err) {
            if (err) {
                console.log(err)
            }
        })

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }
});

尝试判断payment_status的代码

app.post('/api/createCheckoutSession', async (req, res) => {
    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }
            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,
        })

        console.log(session)
        if (session.payment_status == 'paid') {
            cartItem.remove({ user: req.body.user }, function (err) {
                if (err) {
                    console.log(err)
                }
            })
        }

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }
});

解决方案:使用Stripe Webhook监听支付成功事件

这是最可靠且优雅的方案,Webhook是Stripe服务器主动向你的后端发送支付状态变更通知,完全避免前端触发的不可靠性(比如用户直接访问success_url的情况)。

步骤1:修改创建Checkout Session的代码,添加用户ID元数据

在创建session时,通过metadata字段存入用户ID,方便后续Webhook中识别用户:

app.post('/api/createCheckoutSession', async (req, res) => {
    try {
        const session = await stripe.checkout.sessions.create({
            payment_method_types: ['card'],
            mode: 'payment',
            line_items: req.body.items.map(item => {
                const storeItem = storeItems.get(item.id)
                return {
                    price_data: {
                        currency: 'usd',
                        product_data: {
                            name: storeItem.name
                        },
                        unit_amount: storeItem.priceInCents
                    },
                    quantity: item.quantity
                }
            }),
            success_url: `${process.env.SERVER_URL}`,
            cancel_url: `${process.env.SERVER_URL}cart`,
            // 存入用户ID到元数据
            metadata: {
                userId: req.body.user
            }
        })

        res.json({ url: session.url })
    } catch (e) {
        console.log(e)
        res.status(500).json({ error: e.message })
    }
});

步骤2:添加Webhook处理接口

创建专门的接口接收Stripe的支付成功通知,验证请求合法性后清空购物车:

const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET; // 从Stripe后台获取

// 注意要用express.raw解析请求体,不能用json
app.post('/api/stripe-webhook', express.raw({type: 'application/json'}), async (req, res) => {
    const sig = req.headers['stripe-signature'];
    let event;

    try {
        // 验证Stripe签名,确保请求合法
        event = stripe.webhooks.constructEvent(req.body, sig, endpointSecret);
    } catch (err) {
        res.status(400).send(`Webhook Error: ${err.message}`);
        return;
    }

    // 处理支付成功事件
    if (event.type === 'checkout.session.completed') {
        const session = event.data.object;
        const userId = session.metadata.userId;
        
        // 执行清空购物车操作
        try {
            await cartItem.remove({ user: userId });
            console.log(`用户${userId}购物车已清空`);
        } catch (err) {
            console.error('清空购物车失败:', err);
        }
    }

    // 回复Stripe表示已接收
    res.json({ received: true });
});

注意事项

  1. 从Stripe后台的Webhook设置中获取签名密钥(endpointSecret),确保和代码中一致;
  2. 本地调试可以用Stripe CLI转发Webhook事件;
  3. 必须使用express.raw()解析请求体,否则签名验证会失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:24:20