Rails集成Stripe webhook checkout.session.completed报500错误
问题根因
触发500错误的核心原因有两个高概率场景:
Booking.find_by(checkout_session_id: event.data.object.id)未匹配到对应记录时返回nil,后续直接对nil调用update方法会抛出NoMethodError (undefined method 'update' for nil:NilClass),直接返回500。- 即使匹配到了booking记录,若
update操作触发模型层校验失败、前置/后置回调抛出异常,也会导致接口报错。
修复代码
调整checkout.session.completed事件分支的逻辑,增加空值判断、幂等校验和错误日志,修改后完整控制器代码如下:
class WebhooksController < ApplicationController skip_before_action :authenticate_user! skip_before_action :verify_authenticity_token def create payload = request.body.read sig_header = request.env['HTTP_STRIPE_SIGNATURE'] event = nil begin event = Stripe::Webhook.construct_event( payload, sig_header, Rails.application.credentials[:stripe][:webhook] ) rescue JSON::ParserError => e status 400 return rescue Stripe::SignatureVerificationError => e # Invalid signature puts "Signature error" p e return end # Handle the event case event.type when 'checkout.session.completed' session = event.data.object booking = Booking.find_by(checkout_session_id: session.id) # 未找到对应预订时打日志返回,不抛出异常 unless booking Rails.logger.error "[Stripe Webhook] 未找到关联预订,checkout_session_id: #{session.id}" render json: { message: 'booking not found' }, status: :not_found return end # 幂等处理:已支付的订单直接跳过,避免重复事件触发重复逻辑 next if booking.paid? # 处理更新结果,捕获校验错误 unless booking.update(paid: true) Rails.logger.error "[Stripe Webhook] 预订##{booking.id}支付状态更新失败:#{booking.errors.full_messages.join('; ')}" render json: { message: 'update failed', errors: booking.errors.full_messages }, status: :unprocessable_entity return end end render json: { message: 'success' } end end
额外排查点
- 确认创建Stripe Checkout Session的流程中,是否将Stripe返回的session.id正确写入了对应booking记录的
checkout_session_id字段,这是最常见的漏操作。 - 检查Booking模型的回调逻辑(
before_save/before_update/after_*系列),确认更新paid字段时不会触发其他依赖缺失的逻辑。 - 本地调试可使用Stripe CLI将webhook事件转发到本地服务,直接查看控制台抛出的完整错误栈,定位效率远高于查看Stripe后台的状态码日志。
内容的提问来源于stack exchange,提问作者Pauli
相关产品推荐
相关产品推荐

