适用于 Rails 3 的最佳订阅计费系统是什么?
结论
如果需要一款功能接近 Chargify 的托管式订阅计费平台,Recurly 通常是最直接的替代方案。它支持套餐、周期扣款、试用、优惠、账单和订阅生命周期管理,也提供 API,可与 Rails 应用集成。
其他选择包括:
- Stripe Billing:API 清晰、生态成熟,适合希望自行控制业务流程的团队。
- Braintree:同时支持支付和周期性计费,适用于需要 PayPal 等支付方式的场景。
- Zuora:功能全面,但实施难度和成本通常更适合计费需求复杂的企业。
- Active Merchant:这是 Rails 的支付网关抽象库,并非完整的订阅计费平台。套餐、续费和催收逻辑通常需要自行实现。
Rails 3 及其常用 Ruby 版本早已停止维护,当前支付 SDK 不一定能安装在旧项目中。选型时,应先确认供应商是否仍提供兼容项目 Ruby 版本的 SDK。如果无法兼容,可以直接调用 HTTPS API,或者将计费功能拆分到使用受支持运行环境的新服务中。
如何选择
除了是否支持订阅,还要确认以下能力:
- 套餐升级和降级能否按比例计费。
- 是否支持试用期、优惠券、税费和多币种。
- 扣款失败后能否自动重试并进入催收流程。
- Webhook 是否提供完善的签名验证。
- 是否允许导出客户、订阅和交易数据,以免被供应商锁定。
- API 是否支持幂等请求,避免网络重试造成重复订阅或重复扣款。
- 是否满足业务所在地区对税务、发票和数据合规的要求。
如果需求与 Chargify 基本一致,可以先验证 Recurly。如果更看重开发体验和灵活性,可以优先验证 Stripe Billing。
Rails 3 中的集成方式
可以将供应商 API 封装在独立的 gateway 中,避免控制器或业务模型直接依赖某个 SDK。以后更换计费平台时,只需替换适配器。
# app/services/billing_gateway.rb
class BillingGateway
def initialize(client)
@client = client
end
def create_customer(attributes)
@client.create_customer(attributes)
end
def create_subscription(customer_id, plan_id)
@client.create_subscription(
:customer_id => customer_id,
:plan_id => plan_id
)
end
def cancel_subscription(subscription_id)
@client.cancel_subscription(subscription_id)
end
end
这里的 client 是项目为 Recurly、Stripe 或 Braintree 编写的适配器。各供应商的实际方法名和参数结构并不相同,具体实现应以所选平台的 API 文档为准。
控制器只负责接收请求并调用业务服务:
class SubscriptionsController < ApplicationController
def create
gateway = BillingGateway.new(configured_billing_client)
subscription = gateway.create_subscription(
current_user.billing_customer_id,
params[:plan_id]
)
current_user.update_attributes(
:billing_subscription_id => subscription.id,
:subscription_status => subscription.status
)
redirect_to account_path, :notice => "订阅已创建"
rescue BillingError => error
Rails.logger.error(error.message)
redirect_to plans_path, :alert => "暂时无法创建订阅,请稍后重试"
end
end
configured_billing_client 和 BillingError 是应用自身的抽象,并非某家供应商的固定 API。适配器需要将不同供应商的异常统一转换为应用能够处理的错误。
使用 Webhook 同步状态
不能仅凭用户从支付页面跳转回来,就认定订阅已经成功。支付失败、退款、取消和续费等状态通常通过 Webhook 异步通知。
class BillingWebhooksController < ApplicationController
skip_before_filter :verify_authenticity_token
def create
payload = request.raw_post
signature = request.headers["HTTP_X_BILLING_SIGNATURE"]
event = billing_webhook_verifier.verify(payload, signature)
case event.type
when "subscription.activated"
update_subscription(event, "active")
when "subscription.canceled"
update_subscription(event, "canceled")
when "payment.failed"
update_subscription(event, "past_due")
end
head :ok
rescue InvalidWebhookSignature
head :unauthorized
end
private
def update_subscription(event, status)
user = User.find_by_billing_subscription_id(event.subscription_id)
user.update_attributes(:subscription_status => status) if user
end
end
示例中的事件名称和签名请求头只用于说明适配器的设计,不能直接视为某个供应商的真实字段。实现时必须按照平台要求处理签名算法、事件类型和重放防护。
重要注意事项
- 不要在 Rails 数据库中保存完整银行卡号、CVC 等敏感信息。应使用供应商提供的托管支付页面或前端令牌化方案。
- Webhook 可能重复发送,也可能乱序到达。需要保存供应商的事件 ID,并确保事件处理具有幂等性。
- 本地订阅状态只是缓存。发生争议时,应通过 API 查询供应商侧的最终状态。
- 创建客户和订阅时需要记录远端 ID,但不要将业务权限永久绑定到某个供应商特有的状态名称。
- Rails 3 项目可能受到旧 TLS、Ruby/OpenSSL 和根证书的限制。即使 API 设计符合需求,也要在测试环境中验证 HTTPS 连接。
- 不要为了安装现代支付 SDK 而盲目升级单个 gem,因为它可能要求更高版本的 Ruby 或 Rails。如果旧运行环境无法安全支持当前 API,拆分独立的计费服务通常比继续固定旧 SDK 更稳妥。
综合比较,Recurly 与 Chargify 最为接近,而 Stripe Billing 的 API 和扩展性通常更有吸引力。最终选型前,可以做一个小型验证项目,依次测试创建客户、开始订阅、变更套餐、模拟扣款失败、取消订阅,并完整处理 Webhook。
备注:内容仅供参考。
