IHP框架中的Stripe支付集成指南
前言
在现代Web应用中,支付功能是许多SaaS产品的核心需求。本文将详细介绍如何在IHP框架中集成Stripe支付系统,实现完整的订阅式支付流程。
准备工作
环境配置
首先需要在项目中添加ihp-stripe
依赖。修改default.nix
文件:
let
haskellDeps = p: with p; [
ihp-stripe
# 其他依赖...
];
然后在Config/Config.hs
中添加Stripe配置模块:
import IHP.Stripe.Config
config :: ConfigBuilder
config = do
-- 其他配置...
initStripe
API密钥设置
在启动脚本中添加Stripe API密钥:
export STRIPE_WEBHOOK_SECRET_KEY="your_webhook_secret"
export STRIPE_PUBLIC_KEY="your_public_key"
export STRIPE_SECRET_KEY="your_secret_key"
建议在开发阶段使用测试环境的API密钥。
订阅系统实现
数据模型设计
- 计划表(plans):存储不同的订阅计划
CREATE TABLE plans (
id UUID PRIMARY KEY,
name TEXT NOT NULL,
stripe_price_id TEXT NOT NULL
);
- 订阅表(subscriptions):记录用户订阅信息
CREATE TABLE subscriptions (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
starts_at TIMESTAMP WITH TIME ZONE,
ends_at TIMESTAMP WITH TIME ZONE,
is_active BOOLEAN,
stripe_subscription_id TEXT,
plan_id UUID REFERENCES plans(id),
quantity INT
);
- 用户表扩展:添加支付相关字段
ALTER TABLE users ADD COLUMN stripe_customer_id TEXT;
ALTER TABLE users ADD COLUMN plan_id UUID REFERENCES plans(id);
ALTER TABLE users ADD COLUMN subscription_id UUID REFERENCES subscriptions(id);
支付流程实现
- 创建Checkout控制器:
data CheckoutSessionsController
= CheckoutSuccessAction
| CheckoutCancelAction
| CreateCheckoutSessionAction
- 支付会话创建:
action CreateCheckoutSessionAction = do
plan <- query @Plan |> fetchOne
session <- Stripe.send CreateCheckoutSession
{ successUrl = urlTo CheckoutSuccessAction
, cancelUrl = urlTo CheckoutCancelAction
, mode = "subscription"
, customer = currentUser.stripeCustomerId
, lineItem = LineItem plan.stripePriceId 1
}
redirectToUrl session.url
- 支付结果处理:
action CheckoutSuccessAction = do
setSuccessMessage "订阅成功!"
redirectToPath "/"
action CheckoutCancelAction = do
setErrorMessage "支付已取消"
redirectToPath "/"
Webhook集成
创建Webhook控制器处理Stripe事件:
instance StripeEventController where
on CheckoutSessionCompleted { subscriptionId, customer, metadata } = do
-- 处理支付成功事件
user <- fetch userId
subscription <- newRecord @Subscription
|> set #userId user.id
|> set #stripeSubscriptionId subscriptionId
|> createRecord
pure ()
进阶功能实现
账单管理门户
允许用户自主管理订阅:
action OpenBillingPortalAction = do
portal <- Stripe.send CreateBillingPortalSession
{ customer = currentUser.stripeCustomerId
, returnUrl = urlTo StartpageAction
}
redirectToUrl portal.url
发票管理
- 发票表设计:
CREATE TABLE invoices (
id UUID PRIMARY KEY,
subscription_id UUID REFERENCES subscriptions(id),
stripe_invoice_id TEXT,
invoice_url TEXT,
invoice_pdf TEXT,
total INT,
currency TEXT
);
- 发票Webhook处理:
on InvoiceFinalized { subscriptionId, invoiceUrl } = do
subscription <- fetchBy stripeSubscriptionId subscriptionId
invoice <- newRecord @Invoice
|> set #subscriptionId subscription.id
|> set #invoiceUrl invoiceUrl
|> createRecord
pure ()
最佳实践建议
-
测试策略:
- 始终在开发环境使用Stripe测试模式
- 模拟各种支付场景(成功、失败、退款等)
-
安全考虑:
- 妥善保管API密钥
- 验证Webhook签名
- 实现CSRF保护
-
用户体验优化:
- 提供清晰的支付状态反馈
- 设计友好的错误处理流程
- 实现本地化的价格显示
常见问题排查
-
Webhook未触发:
- 检查Stripe CLI配置
- 验证端点URL是否正确
- 确认事件订阅设置
-
支付会话问题:
- 检查价格ID格式
- 验证客户ID有效性
- 确认支付方式配置
-
数据库同步延迟:
- 实现适当的重试机制
- 添加日志记录关键步骤
- 考虑使用后台任务处理复杂操作
通过本文的指导,开发者可以在IHP框架中快速实现完整的Stripe支付集成,为应用添加专业的订阅支付功能。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考