使用Stripe v12.9.0发起支付时触发内部服务器错误求助
Stripe v12.9.0支付请求触发内部服务器错误排查
使用Stripe v12.9.0开发支付功能时,发起支付请求后出现内部服务器错误,以下是相关代码及排查方向:
后端代码
const ErrorHander = require("../utils/errorhander"); const cachasycError = require("../middleware/cachasycError"); const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); // 处理支付 exports.paymentProcess = cachasycError(async (req, res, next) => { const paymentIntent = await stripe.paymentIntents.create({ amount: req.body.amount, currency: "usd", payment_method_types: ["card"], metadata: { company: "Ecommerce", }, }); res.status(200).json({ success: true, client_secret: paymentIntent.client_secret, }); }); // 返回公钥 exports.publicstripeapikey = cachasycError(async (req, res, next) => { res.status(200).json({ success: true, stripeapikey: process.env.STRIPE_API_KEY, }); });
前端代码
import React, { Fragment, useEffect, useRef } from "react"; import CheckoutSteps from "../cart/CheckoutSteps"; import { useSelector, useDispatch } from "react-redux"; import MetaData from "../layout/Header/Metadata"; import Typography from "@mui/material/Typography"; import { ToastContainer, toast } from "react-toastify"; import { CardNumberElement, CardCvcElement, CardExpiryElement, useStripe, useElements, } from "@stripe/react-stripe-js"; import axios from "axios"; import "./payment.css"; import CreditCardIcon from "@mui/icons-material/CreditCard"; import EventIcon from "@mui/icons-material/Event"; import VpnKeyIcon from "@mui/icons-material/VpnKey"; import { useNavigate } from "react-router-dom"; // import { createOrder, clearErrors } from "../../actions/orderAction"; const Payment = () => { const history = useNavigate(); const orderInfo = JSON.parse(sessionStorage.getItem("orderInfo")); // const dispatch = useDispatch(); const stripe = useStripe(); const elements = useElements(); const payBtn = useRef(null); const { shippingInfo, cartItems } = useSelector((state) => state.cart); const { user } = useSelector((state) => state.user); // const { error } = useSelector((state) => state.newOrder); const paymentData = { amount: Math.round(orderInfo.totalPrice * 100), }; const order = { shippingInfo, orderItems: cartItems, itemsPrice: orderInfo.subtotal, taxPrice: orderInfo.tax, shippingPrice: orderInfo.shippingCharges, totalPrice: orderInfo.totalPrice, }; const submitHandler = async (e) => { e.preventDefault(); payBtn.current.disabled = true; try { const config = { headers: { "Content-Type": "application/json", }, }; const { data } = await axios.post( "/api/v1/payment/process", paymentData, config ); const client_secret = data.client_secret; if (!stripe || !elements) return; const result = await stripe.confirmCardPayment(client_secret, { payment_method: { card: elements.getElement(CardNumberElement), billing_details: { name: user.name, email: user.email, address: { line1: shippingInfo.address, city: shippingInfo.city, state: shippingInfo.state, postal_code: shippingInfo.pinCode, country: shippingInfo.country, }, }, }, }); if (result.error) { payBtn.current.disabled = false; toast(result.error.message); } else { if (result.paymentIntent.status === "succeeded") { order.paymentInfo = { id: result.paymentIntent.id, status: result.paymentIntent.status, }; console.log("order"); console.log(order); // dispatch(createOrder(order)); history("/success"); } else { alert.error("There's some issue while processing payment "); } } } catch (error) { payBtn.current.disabled = false; // alert.error(error.response.data.message); } }; useEffect(() => { // if (error) { // alert.error(error); // dispatch(clearErrors()); // } }, [alert]); return ( <Fragment> <ToastContainer /> <MetaData title="Payment" /> <CheckoutSteps activeStep={2} /> <div className="paymentContainer"> <form className="paymentForm" onSubmit={(e) => submitHandler(e)}> <Typography>Card Info</Typography> <div> <CreditCardIcon /> <CardNumberElement className="paymentInput" /> </div> <div> <EventIcon /> <CardExpiryElement className="paymentInput" /> </div> <div> <VpnKeyIcon /> <CardCvcElement className="paymentInput" /> </div> <input type="submit" value={`Pay - ₹${orderInfo && orderInfo.totalPrice}`} ref={payBtn} className="paymentFormBtn" /> </form> </div> </Fragment> ); }; export default Payment;
排查方向
1. 环境变量有效性验证
- 检查
process.env.STRIPE_SECRET_KEY是否正确配置,确保是Stripe提供的测试/生产秘钥,无拼写错误(原文中出现的stipe是笔误,应为stripe)。 - 在后端代码中添加日志
console.log(process.env.STRIPE_SECRET_KEY),确认变量是否成功加载。
2. 支付金额参数校验
- Stripe要求
amount必须是最小货币单位的整数(如USD的分、INR的派萨),前端Math.round(orderInfo.totalPrice * 100)需确保orderInfo.totalPrice是有效数字,计算结果为正整数。 - 后端需对
req.body.amount做校验,避免无效参数传递给Stripe API:if (!req.body.amount || typeof req.body.amount !== 'number' || req.body.amount <= 0) { return next(new ErrorHander('Invalid payment amount', 400)); }
3. 错误捕获与日志完善
- 后端的
cachasycError应为catchAsyncError(拼写错误),需确认该中间件是否正确捕获异步错误并传递给ErrorHander。 - 在
paymentProcess中添加Stripe API错误捕获,打印详细错误信息:exports.paymentProcess = cachasycError(async (req, res, next) => { try { const paymentIntent = await stripe.paymentIntents.create({ amount: req.body.amount, currency: "usd", payment_method_types: ["card"], metadata: { company: "Ecommerce", }, }); res.status(200).json({ success: true, client_secret: paymentIntent.client_secret, }); } catch (err) { console.error('Stripe Error:', err); next(new ErrorHander(err.message, err.statusCode || 500)); } });
4. 路由与请求配置检查
- 确认后端
/api/v1/payment/process路由已配置为POST方法,且前端请求地址与后端路由一致。 - 检查跨域配置,但内部服务器错误通常由后端逻辑或Stripe API调用失败导致,跨域问题一般返回4xx状态码。
5. 前端初始化验证
- 确保前端已通过
loadStripe和Elements组件正确初始化Stripe:import { loadStripe } from '@stripe/stripe-js'; import { Elements } from '@stripe/react-stripe-js'; const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLIC_KEY); function App() { return ( <Elements stripe={stripePromise}> <Payment /> </Elements> ); }
内容的提问来源于stack exchange,提问作者ritik Kumar Sharma
相关产品推荐
相关产品推荐

