Flutter从Firestore获取Stripe checkout_session URL报错排查
问题原因
你创建checkout_session文档后立刻监听它的快照,此时文档刚写入你手动设置的price/success_url/cancel_url三个字段,Stripe的Firebase扩展还没完成异步处理并写入url字段,所以第一次触发快照时url根本不存在,调用ds.get("url")就会抛出"字段不存在"的错误。
第二次点击时,之前创建的文档已经被Stripe处理完毕,url已经生成并存入Firestore,所以能正常获取。
修复方案
1. 安全获取url字段
不要直接用ds.get("url")(该方法在字段不存在时会直接抛出异常),改用两种安全方式:
- 方式一:通过
data()加空安全访问:ds.data()?['url'] - 方式二:用
get()的默认值参数:ds.get("url", defaultValue: null)
2. 仅在url有效时执行跳转
监听快照时,只有拿到非空的url再启动结账页面,避免无效操作。
3. 取消Stream订阅防止内存泄漏
监听快照会返回StreamSubscription对象,跳转后要及时取消订阅,避免内存泄漏。
修改后的代码示例
将按钮的onTap逻辑替换为以下代码:
GestureDetector( onTap: () async { FirebaseFirestore _firestore = FirebaseFirestore.instance; DocumentReference documentReference = await _firestore .collection("users") .doc(fireStoreUser.uid) .collection("checkout_sessions") .add({ "price": membershipPriceId, "success_url": "https://checkout.stripe.com/success", "cancel_url": "https://checkout.stripe.com/cancel", }); // 保存订阅对象,用于后续取消 late StreamSubscription<DocumentSnapshot> subscription; subscription = documentReference.snapshots().listen((ds) async { if (ds.exists) { // 安全获取url,不存在时返回null var url = ds.data()?['url']; if (url != null) { // 取消订阅,避免重复触发跳转 subscription.cancel(); var res = await Navigator.push( context, MaterialPageRoute( builder: (context) => CheckoutScreen(url: url), ), ); if (res == "success") { logger.i("Payment completed"); } else { logger.w("Payment failed"); } } } }); }, // 其他代码保持不变 )
额外建议
- 确认Stripe的Firebase扩展已正确配置,能自动处理checkout_session文档并写入
url字段。 - 点击按钮后可添加加载状态(比如显示CircularProgressIndicator),直到拿到
url再跳转,提升用户体验。
内容的提问来源于stack exchange,提问作者Seth
相关产品推荐
相关产品推荐

