在Nuxt 3中集成Stripe实现预订系统的技术求助
汽车预订系统(Nuxt + Stripe)实现指导
核心业务对应Stripe方案
- 延迟收款逻辑:使用Stripe的「Payment Intent」并设置
capture_method: 'manual',客户完成支付后资金处于预授权状态,仅当管理员审核通过后,再手动捕获资金;审核不通过则取消Payment Intent,自动完成退款。 - 支付信息安全存储:创建Stripe「Customer」对象,将客户的支付方式(如银行卡)关联到该Customer,仅在系统中存储Stripe返回的
customer_id和payment_method_id,避免直接存储敏感支付数据。 - 额外费用收取:利用已关联到Customer的支付方式,直接创建新的Payment Intent完成扣款,无需客户再次输入支付信息。
Nuxt端具体实现步骤
1. 安装依赖
在项目中安装Stripe相关包:
# 前端Stripe SDK npm install @stripe/stripe-js # 后端Stripe SDK(用于服务器端API) npm install stripe
2. 配置Stripe密钥
在Nuxt的环境变量文件(.env)中添加:
# 服务器端用的Secret Key(绝对不能暴露到前端) STRIPE_SECRET_KEY=sk_xxx # 前端用的Publishable Key STRIPE_PUBLISHABLE_KEY=pk_xxx
3. 前端:集成Stripe Elements收集支付信息
在预订页面组件中,加载Stripe.js并初始化Elements:
<template> <div> <!-- Stripe Elements容器 --> <div id="card-element"></div> <button @click="handlePayment">提交预订并支付</button> </div> </template> <script setup> import { loadStripe } from '@stripe/stripe-js' import { ref, onMounted } from 'vue' const stripePromise = loadStripe(process.env.STRIPE_PUBLISHABLE_KEY) let elements = null onMounted(async () => { const stripe = await stripePromise elements = stripe.elements() // 创建卡片元素 const cardElement = elements.create('card') cardElement.mount('#card-element') }) const handlePayment = async () => { const stripe = await stripePromise // 先调用Nuxt后端API创建Customer和Payment Intent const { data: { clientSecret } } = await useFetch('/api/create-payment-intent', { method: 'POST', body: { amount: 1000, // 预订金额(单位:分) bookingId: 'your-booking-id' // 关联你的系统预订ID } }) // 确认支付 const { error } = await stripe.confirmCardPayment(clientSecret, { payment_method: { card: elements.getElement('card'), billing_details: { name: '客户姓名', email: '客户邮箱' } } }) if (error) { // 处理支付错误 console.error(error.message) } else { // 支付预授权成功,跳转至预订等待审核页面 navigateTo('/booking-pending') } } </script>
4. 后端:创建Customer与Payment Intent
在Nuxt的server/api/create-payment-intent.ts中编写API:
import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20' // 使用最新API版本 }) export default defineEventHandler(async (event) => { const body = await readBody(event) const { amount, bookingId } = body // 1. 创建Stripe Customer const customer = await stripe.customers.create({ email: '客户邮箱', // 可从前端传入 metadata: { bookingId } // 关联预订ID }) // 2. 创建Payment Intent(手动捕获模式) const paymentIntent = await stripe.paymentIntents.create({ amount, currency: 'cny', // 根据你的业务设置币种 customer: customer.id, capture_method: 'manual', metadata: { bookingId } }) // 3. 将customer_id和payment_intent_id存入你的数据库,关联对应预订记录 // 这里省略数据库操作逻辑 return { clientSecret: paymentIntent.client_secret } })
5. 审核后收款/退款逻辑
编写后端API处理管理员审核操作:
- 审核通过,捕获资金:
server/api/capture-payment.ts
import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20' }) export default defineEventHandler(async (event) => { const body = await readBody(event) const { paymentIntentId } = body // 捕获预授权的资金 const paymentIntent = await stripe.paymentIntents.capture(paymentIntentId) // 更新数据库中预订状态为「已确认」 // 省略数据库操作 return { success: true, paymentIntent } })
- 审核不通过,取消支付并退款:
server/api/cancel-payment.ts
import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20' }) export default defineEventHandler(async (event) => { const body = await readBody(event) const { paymentIntentId } = body // 取消Payment Intent,自动退款 const paymentIntent = await stripe.paymentIntents.cancel(paymentIntentId) // 更新数据库中预订状态为「已取消」 // 省略数据库操作 return { success: true, paymentIntent } })
6. 额外费用收取逻辑
当需要收取车辆损坏/里程超额费用时,调用后端API:server/api/charge-extra.ts
import Stripe from 'stripe' const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, { apiVersion: '2024-06-20' }) export default defineEventHandler(async (event) => { const body = await readBody(event) const { customerId, amount, reason } = body // 使用已关联的支付方式创建新的Payment Intent并自动捕获 const paymentIntent = await stripe.paymentIntents.create({ amount, currency: 'cny', customer: customerId, payment_method: 'pm_xxx', // 从数据库中取出该Customer关联的支付方式ID confirm: true, // 自动确认并捕获资金 metadata: { reason } }) // 记录额外费用到数据库 // 省略数据库操作 return { success: true, paymentIntent } })
关键注意事项
- 敏感操作全走后端:Stripe Secret Key绝对不能出现在前端代码中,所有与Stripe的交互(创建Customer、捕获/取消支付等)必须通过Nuxt服务器端API完成。
- Webhook处理异步事件:配置Stripe Webhook监听
payment_intent.succeeded、payment_intent.canceled等事件,确保系统状态与Stripe同步(比如支付失败时更新预订状态)。 - PCI合规:使用Stripe Elements收集支付信息,无需自己处理银行卡号等敏感数据,自动满足PCI合规要求。
- 错误处理:在前端和后端都要处理Stripe返回的错误(比如支付被拒绝、网络异常等),给用户清晰的提示。
内容的提问来源于stack exchange,提问作者Akram Trimech
相关产品推荐
相关产品推荐

