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

React Native中Stripe支付确认异常求助:支付成功却报错

React Native Stripe支付矛盾问题:前端报错但后台支付成功的解决方法

点击支付按钮后,控制台输出“Card details not complete”错误,弹出支付失败提示,但Stripe后台显示支付已成功。

问题根源

你的后端代码在创建Payment Intent时设置了confirm: true和off_session: true,这会让Stripe直接在后端完成支付确认流程。而前端又调用了confirmPayment函数再次尝试确认同一个Payment Intent——此时该Intent已经处于成功状态,二次确认就会触发“Card details not complete”的错误,但实际上支付已经在后端完成了。

解决方案

根据支付场景选择对应方案,核心原则是不要同时在后端和前端确认同一个Payment Intent:

方案一:后端创建未确认的Payment Intent,由前端完成确认

适合用户在场的主动支付场景(on-session),调整后端代码移除自动确认逻辑,让前端完成支付确认:

修改后的后端代码

app.post('/create-payment-intent', async (req, res) => {
    const { amount, stripeCustomerId } = req.body;

    try {
        const paymentIntent = await stripe.paymentIntents.create({
            amount: amount,
            currency: 'usd',
            customer: stripeCustomerId,
            // 移除confirm: true和payment_method参数,交由前端处理支付方式
            setup_future_usage: 'off_session', // 可选:如果需要后续自动扣费可添加
        });

        res.send({ clientSecret: paymentIntent.client_secret });
    } catch (error) {
        console.error('Error creating payment intent:', error);
        res.status(500).send({ error: error.message });
    }
});

前端代码调整

保持原有handleConfirmPayment逻辑,确保传入正确的支付方式ID:

const handleConfirmPayment = async () => {
    console.log('Starting payment confirmation...');

    if (!selectedPaymentMethodId) {
        console.log('No payment method selected.');
        Alert.alert('Error', 'No payment method selected');
        return;
    }

    console.log(`Selected payment method ID: ${selectedPaymentMethodId}`);

    try {
        console.log('Creating payment intent...');
        const response = await axios.post('/create-payment-intent', {
            amount: 3006, // 金额单位为分($30.00)
            stripeCustomerId: "your-actual-customer-id", // 动态获取真实客户ID,不要硬编码
        });

        console.log('Payment intent response:', response.data);
    
        const { clientSecret } = response.data;
    
        if (!clientSecret) {
            console.error('Failed to get client secret from the backend');
            Alert.alert('Payment failed', 'Unable to process the payment.');
            return;
        }

        console.log(`Confirming payment with client secret: ${clientSecret}`);
        const { error } = await confirmPayment(clientSecret, {
            paymentMethodType: 'Card', 
            paymentMethodId: selectedPaymentMethodId,
        });

        if (error) {
            console.error('Payment confirmation error:', error);
            Alert.alert('Payment failed', error.message);
        } else {
            console.log('Payment successful!');
            Alert.alert('Payment successful', 'Your payment was successful!');
        }
    } catch (error) {
        console.error('Payment error:', error);
        Alert.alert('Payment failed', 'There was an issue with your payment.');
    }
};

方案二:后端完成off_session支付,前端仅验证状态

适合用户不在场的自动扣费场景,后端创建并确认Payment Intent后,前端只需要验证支付状态,无需调用confirmPayment:

修改后的后端代码

保留自动确认逻辑,同时返回Payment Intent的状态:

app.post('/create-payment-intent', async (req, res) => {
    const { amount, stripeCustomerId } = req.body;

    try {
        const customer = await stripe.customers.retrieve(stripeCustomerId);
        const defaultPaymentMethodId = customer.invoice_settings.default_payment_method;

        if (!defaultPaymentMethodId) {
            return res.status(400).send({ error: 'No default payment method found for the customer' });
        }

        const paymentIntent = await stripe.paymentIntents.create({
            amount: amount,
            currency: 'usd',
            customer: stripeCustomerId,
            payment_method: defaultPaymentMethodId,
            confirm: true,
            off_session: true,
        });

        // 返回状态和clientSecret,供前端验证
        res.send({ 
            clientSecret: paymentIntent.client_secret,
            status: paymentIntent.status
        });
    } catch (error) {
        console.error('Error creating payment intent:', error);
        res.status(500).send({ error: error.message });
    }
});

前端代码调整

移除confirmPayment调用,改为验证Payment Intent状态:

import { retrievePaymentIntent } from '@stripe/stripe-react-native';

const handleConfirmPayment = async () => {
    console.log('Starting payment...');

    try {
        console.log('Creating payment intent...');
        const response = await axios.post('/create-payment-intent', {
            amount: 3006, // 金额单位为分($30.00)
            stripeCustomerId: "your-actual-customer-id", // 动态获取真实客户ID,不要硬编码
        });

        console.log('Payment intent response:', response.data);
    
        const { clientSecret, status } = response.data;
    
        if (!clientSecret) {
            console.error('Failed to get client secret from the backend');
            Alert.alert('Payment failed', 'Unable to process the payment.');
            return;
        }

        // 优先使用后端返回的状态,否则主动查询
        let paymentStatus = status;
        if (!paymentStatus) {
            const { paymentIntent } = await retrievePaymentIntent(clientSecret);
            paymentStatus = paymentIntent.status;
        }

        if (paymentStatus === 'succeeded') {
            console.log('Payment successful!');
            Alert.alert('Payment successful', 'Your payment was successful!');
        } else {
            console.error('Payment failed with status:', paymentStatus);
            Alert.alert('Payment failed', `Payment failed with status: ${paymentStatus}`);
        }
    } catch (error) {
        console.error('Payment error:', error);
        Alert.alert('Payment failed', 'There was an issue with your payment.');
    }
};

关键注意事项

  • on-session支付(用户在场):必须由前端完成支付确认,后端仅创建Payment Intent。
  • off-session支付(用户不在场):后端完成确认后,前端仅需验证状态,不要重复调用确认接口。
  • 确保stripeCustomerId是动态获取的真实客户ID,禁止硬编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 04:32:05