Flutter Web中如何优雅监听Stripe Checkout支付状态?
Flutter Web集成Stripe:替代轮询的优雅支付状态监听方案
问题背景
我在Flutter Web应用中集成Stripe,已创建Stripe Checkout会话与Firebase云函数,通过url_launcher包可打开支付页面,但无法掌控后续支付状态。目前采用轮询Stripe API的方式查询支付状态,代码如下:
do { res = await http.get(Uri.parse("https://api.stripe.com/v1/checkout/sessions/XXXUUUU"), headers: headers); if (res.statusCode != 200) throw Exception('http.post error: statusCode= ${res.statusCode}'); else { risultato = jsonDecode(res.body); print(risultato["payment_status"]); await Future.delayed(Duration(seconds: 2)); } } while ((risultato["payment_status"] == "unpaid") || !pagamentoInCorso);
想了解是否有更优雅的实现方式,比如使用Stream?
优雅实现方案
1. 用Stream封装轮询逻辑
把轮询逻辑包装成Stream,利用响应式特性简化UI层状态监听,比原生循环更易维护:
Stream<String> pollPaymentStatus(String sessionId, Map<String, String> headers) async* { bool keepPolling = true; while (keepPolling) { try { final res = await http.get( Uri.parse("https://api.stripe.com/v1/checkout/sessions/$sessionId"), headers: headers, ); if (res.statusCode != 200) { throw Exception('http.get error: statusCode= ${res.statusCode}'); } final data = jsonDecode(res.body); final status = data["payment_status"] as String; yield status; // 状态达标或支付取消时停止轮询 if (status == "paid" || !pagamentoInCorso) { keepPolling = false; } else { await Future.delayed(const Duration(seconds: 2)); } } catch (e) { yield "error"; await Future.delayed(const Duration(seconds: 2)); } } } // 使用示例 pollPaymentStatus("XXXUUUU", headers).listen((status) { switch(status) { case "paid": // 处理支付成功逻辑 break; case "unpaid": // 显示支付中状态 break; case "error": // 处理请求错误 break; } });
2. Stripe Webhook + Firebase实时数据库/Cloud Firestore(推荐)
完全替代轮询,实现状态实时推送:
- 在Stripe后台配置Webhook,监听
checkout.session.completed、checkout.session.expired事件,将接收地址指向你的Firebase云函数。 - 云函数收到Stripe事件后,把支付状态写入Firebase实时数据库或Cloud Firestore对应文档。
- Flutter Web端监听数据库中会话ID对应的状态变化:
// 监听Firestore中支付状态更新 FirebaseFirestore.instance .collection("payment_sessions") .doc("XXXUUUU") .snapshots() .listen((snapshot) { if (snapshot.exists) { final status = snapshot.data()?["payment_status"]; if (status == "paid") { // 执行支付成功逻辑 } else if (status == "expired") { // 处理会话过期逻辑 } } });
这种方式无需前端主动请求,状态更新及时且减少API调用量。
3. 利用Checkout会话重定向特性
创建Checkout会话时,配置success_url和cancel_url为你的Flutter Web应用路由(例如https://yourapp.com/payment-success?session_id={CHECKOUT_SESSION_ID})。用户支付完成/取消后会跳转回应用,在对应路由页面通过session_id一次性查询支付状态即可,无需轮询。
内容的提问来源于stack exchange,提问作者Maurizio Mancini
相关产品推荐
相关产品推荐

