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

客户通过Stripe支付成功后如何将预订支付状态修改为已支付

问题根源

你当前的代码仅完成了Stripe结账会话的创建,没有处理支付成功后的状态更新逻辑。注意:绝对不能通过success_url对应的页面动作来修改支付状态,原因有两个:

  • 用户支付完成后可能因网络问题没跳转到成功页,状态会永远卡住
  • 恶意用户可以直接访问成功页地址,无需支付就能把订单标记为已付款,存在严重安全漏洞

Stripe的支付结果是异步通知的,必须通过官方的Webhook机制接收支付成功事件,再更新本地订单状态,这是唯一可靠的实现方式。

实现步骤

1. 修改结账会话创建逻辑,绑定预订ID

创建Stripe Session时把对应预订ID存在元数据里,后续Webhook收到事件时就能匹配到对应的本地订单,同时修正金额计算的精度隐患:

class CheckoutController < ApplicationController
  def create
    product = Listing.find(params[:listing_id])
    booking = Booking.find(params[:id])
    duration = (booking.end_date - booking.start_date).to_i + 1
    @session = Stripe::Checkout::Session.create({
      payment_method_types: ['card'],
      line_items: [{
        name: product.name,
        amount: (product.price * 100).to_i,
        currency: "gbp",
        quantity: duration
      }],
      mode: 'payment',
      # 绑定预订ID到会话元数据
      metadata: {
        booking_id: booking.id
      },
      success_url: "#{bookings_url}?session_id={CHECKOUT_SESSION_ID}",
      cancel_url: bookings_url
    })
    respond_to do |format|
      format.js
    end
  end
end

2. 添加Webhook路由

在路由文件中新增Stripe Webhook的接收端点:

# config/routes.rb
post '/stripe/webhook', to: 'stripe_webhooks#create'

3. 编写Webhook处理逻辑

新建对应的控制器,注意要做Stripe请求签名校验,防止伪造请求篡改订单状态:

class StripeWebhooksController < ApplicationController
  # 跳过CSRF校验,Stripe发请求不会携带站点CSRF凭证
  skip_before_action :verify_authenticity_token

  def create
    payload = request.body.read
    sig_header = request.env['HTTP_STRIPE_SIGNATURE']
    endpoint_secret = ENV['STRIPE_WEBHOOK_SECRET']
    event = nil

    begin
      event = Stripe::Webhook.construct_event(payload, sig_header, endpoint_secret)
    rescue JSON::ParserError
      return head 400
    rescue Stripe::SignatureVerificationError
      return head 400
    end

    # 仅处理支付完成的事件
    if event.type == 'checkout.session.completed'
      session = event.data.object
      booking = Booking.find(session.metadata.booking_id)
      # 避免重复更新状态
      booking.update!(paid: true) unless booking.paid
    end

    head 200
  end
end

4. 配置Stripe端的Webhook规则

  • 本地开发时用Stripe CLI做端口转发,执行命令stripe listen --forward-to localhost:3000/stripe/webhook,将CLI输出的Webhook签名密钥配置到本地环境变量STRIPE_WEBHOOK_SECRET即可调试
  • 上线后在Stripe后台Webhook配置页,添加线上端点地址https://你的站点域名/stripe/webhook,选择监听checkout.session.completed事件,将生成的签名密钥配置到生产环境变量即可
注意事项
  • success_url仅用于前端向用户展示支付成功的提示,不要在该路由的逻辑里写任何订单状态更新的代码
  • 必须开启Webhook签名校验,否则任何人都可以构造假请求将所有订单标记为已支付
  • 金额字段必须转为整数再传给Stripe,浮点数精度问题会导致支付金额错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 22:54:25