React-Rails集成Stripe支付遇阻:无法展示支付表单UI
React + Rails 集成Stripe支付表单实现步骤
前端React部分
- 安装Stripe依赖
npm install @stripe/react-stripe-js @stripe/stripe-js
- 实现支付表单组件
import { useState } from 'react'; import { loadStripe } from '@stripe/stripe-js'; import { Elements, CardElement, useStripe, useElements } from '@stripe/react-stripe-js'; // 替换为你的Stripe公钥(从Stripe控制台获取) const stripePromise = loadStripe('pk_test_your_public_key'); const PaymentForm = () => { const stripe = useStripe(); const elements = useElements(); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const handleSubmit = async (e) => { e.preventDefault(); if (!stripe || !elements) return; setLoading(true); setError(null); // 调用Rails后端获取支付意图的客户端密钥 const response = await fetch('/api/payment_intents', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ amount: 1000 }) // 金额单位为分,示例为10美元 }); const { client_secret } = await response.json(); // 确认卡片支付 const { error: stripeError, paymentIntent } = await stripe.confirmCardPayment(client_secret, { payment_method: { card: elements.getElement(CardElement), billing_details: { name: '用户姓名' // 可替换为用户输入的真实姓名 } } }); if (stripeError) { setError(stripeError.message); } else if (paymentIntent.status === 'succeeded') { alert('支付成功!'); // 添加支付成功后的业务逻辑,比如跳转订单详情页 } setLoading(false); }; return ( <form onSubmit={handleSubmit}> <CardElement options={{ style: { base: { fontSize: '16px', color: '#424770', '::placeholder': { color: '#aab7c4' } }, invalid: { color: '#9e2146' } } }} /> {error && <div style={{ color: 'red', marginTop: '10px' }}>{error}</div>} <button type="submit" disabled={!stripe || loading} style={{ marginTop: '20px', padding: '10px 20px', backgroundColor: '#0070f3', color: 'white', border: 'none', borderRadius: '4px', cursor: loading ? 'not-allowed' : 'pointer' }} > {loading ? '处理中...' : '支付 $10.00'} </button> </form> ); }; // 在页面中使用Elements包裹表单组件 export default function CheckoutPage() { return ( <div style={{ maxWidth: '500px', margin: '50px auto' }}> <h2>完成支付</h2> <Elements stripe={stripePromise}> <PaymentForm /> </Elements> </div> ); }
后端Rails部分
- 添加Stripe依赖到Gemfile
gem 'stripe'
执行bundle install完成安装
- 配置Stripe密钥,新建
config/initializers/stripe.rb:
Rails.configuration.stripe = { publishable_key: ENV['STRIPE_PUBLISHABLE_KEY'], secret_key: ENV['STRIPE_SECRET_KEY'] } Stripe.api_key = Rails.configuration.stripe[:secret_key]
在.env文件中配置密钥:
STRIPE_PUBLISHABLE_KEY=pk_test_your_public_key STRIPE_SECRET_KEY=sk_test_your_secret_key
- 创建支付意图控制器
# app/controllers/api/payment_intents_controller.rb class Api::PaymentIntentsController < ApplicationController skip_before_action :verify_authenticity_token, only: [:create] def create amount = params[:amount].to_i payment_intent = Stripe::PaymentIntent.create( amount: amount, currency: 'usd' # 可根据需求修改货币类型 ) render json: { client_secret: payment_intent.client_secret } rescue Stripe::InvalidRequestError => e render json: { error: e.message }, status: 400 end end
- 添加路由到
config/routes.rb
Rails.application.routes.draw do namespace :api do post 'payment_intents', to: 'payment_intents#create' end # 其他路由配置 end
关键注意事项
- 测试环境使用Stripe测试密钥,生产环境切换为正式密钥。
- 必须通过后端创建支付意图(Payment Intent),这是Stripe强制的安全要求,不能直接在前端生成。
- 建议后端监听Stripe的webhook事件,用来最终确认支付状态,避免前端篡改结果。
内容的提问来源于stack exchange,提问作者Pamphilemkp
相关产品推荐
相关产品推荐

