Stripe支付网关报错:客户cus_xxxx无tok_visa卡片,请求返回400错误
Stripe支付400错误修复:Customer cus_xxxx does not have card with ID tok_visa
问题场景
点击「Pay Now」按钮后,客户端向/api/bookings/bookroom接口发起POST请求,返回400 Bad Request错误,Stripe返回具体错误信息:
Customer cus_xxxx does not have card with ID tok_visa
相关代码
客户端代码
const onToken = async (token) => { console.log(token); const bookingDetails = { room, userid: JSON.parse(localStorage.getItem("currentUser"))._id, fromdate, todate, totalAmount, totaldays: totalDays, token, }; try { setLoading(true); const result = await axios.post("/api/bookings/bookroom", bookingDetails); setLoading(false); Swal.fire( "Congratulations", "Your Room Booked Successfully", "success" ).then((result) => { window.location.href = "/home"; }); } catch (error) { setError(error); Swal.fire("Opps", "Error:" + error, "error"); } setLoading(false); }; return ( <StripeCheckout amount = { totalAmount * 100 } currency = "USD" token = { onToken } stripeKey = "PUBLIC_KEY_STRIPE" > <button className = "btn btn-primary" > Pay Now </button> </StripeCheckout> )
服务端代码(原错误版本)
const express = require("express"); const moment = require("moment"); const stripe = require("stripe")("PIRVATE_KEY"); const { v4: uuidv4 } = require("uuid"); const router = express.Router(); const Booking = require("../models/booking"); const Room = require("../models/room"); router.post("/bookroom", async (req, res) => { const { room, userid, fromdate, todate, totalAmount, totaldays, token } = req.body; try { // 创建客户 const customer = await stripe.customers.create({ email: token.email, source: token.id, }); // 发起支付 const payment = await stripe.charges.create({ amount: totalAmount * 100, customer: customer.id, currency: "USD", receipt_email: token.email, source: "tok_visa", // 错误根源 }, { idempotencyKey: uuidv4(), }); // 支付成功后的预订逻辑 if (payment) { try { const newBooking = new Booking({ room: room.name, roomid: room._id, userid, fromdate: moment(fromdate).format("DD-MM-YYYY"), todate: moment(todate).format("DD-MM-YYYY"), totalamount: totalAmount, totaldays, transactionid: uuidv4(), }); console.log(newBooking); const booking = await newBooking.save(); const roomTmp = await Room.findOne({ _id: room._id }); roomTmp.currentbookings.push({ bookingid: booking._id, fromdate: moment(fromdate).format("DD-MM-YYYY"), todate: moment(todate).format("DD-MM-YYYY"), userid: userid, status: booking.status, }); await roomTmp.save(); res.send("Payment Successful, Your Room is booked"); } catch (error) { return res.status(400).json({ message: error }); } } } catch (error) { return res.status(400).json({ message: error }); } }); module.exports = router;
错误原因
创建支付请求时硬编码了source: "tok_visa",但这个测试token并没有关联到刚刚创建的customer对象上。实际上你已经通过stripe.customers.create将用户提交的真实支付token(token.id)绑定到了新建的customer,此时发起支付只需要指定customer参数即可,Stripe会自动使用该customer的默认支付方式。
修复方案
移除stripe.charges.create中的source: "tok_visa"配置项,修改后的支付请求代码如下:
const payment = await stripe.charges.create({ amount: totalAmount * 100, customer: customer.id, currency: "USD", receipt_email: token.email, }, { idempotencyKey: uuidv4(), });
额外说明
如果后续需要支持用户使用多个支付方式,可以先将支付token附加到customer,再在发起支付时指定对应的支付方式ID,但当前场景下直接依赖customer的默认支付方式即可满足需求。
内容的提问来源于stack exchange,提问作者Yash
相关产品推荐
相关产品推荐

