使用Firebase Stripe订阅扩展时重复创建客户是什么原因?
问题原因
你遇到的重复创建Stripe客户的核心原因是两个云函数的并行执行冲突:
- Firebase Stripe订阅扩展默认有两个触发逻辑:
- 当你在
collection-users集合新增用户文档时,自动触发createCustomer函数创建对应Stripe客户,创建完成后会把生成的Stripe客户ID回写到用户文档的stripeCustomerId字段 - 当你在用户的
checkout_sessions子集合新增文档时,自动触发createCheckoutSession函数创建结账会话,执行时会先查当前用户是否已有stripeCustomerId,如果没有就会自行创建一个Stripe客户
- 当你在
- 你现有代码在用户文档写入完成后立刻调用
subscribe()新增结账会话,导致两个云函数几乎同时启动:createCustomer还没完成客户创建、还没把stripeCustomerId回写到用户文档,createCheckoutSession就已经执行到客户查询步骤,查不到有效ID就触发了重复创建。
解决方案
最可靠的修复方式是修改注册逻辑,不要写完用户文档就立刻创建结账会话,改为监听用户文档的stripeCustomerId字段,等扩展把该字段写入完成后再调用subscribe():
if (agreeToTerms == true && name != '' && surname != '' && companyName != '' && companyActivity != '' ) { auth.createUserWithEmailAndPassword(email, password).then(cred => { return db.collection('collection-users').doc(cred.user.uid).set({ name: name, surname: surname, email: email, companyName: companyName, companyActivity: companyActivity }) }).then(() => { // 改为监听用户文档,等Stripe客户ID生成后再跳转结账 const userDocRef = db.collection('collection-users').doc(firebase.auth().currentUser.uid) const unsubscribe = userDocRef.onSnapshot((snap) => { const userData = snap.data() if (userData?.stripeCustomerId) { unsubscribe() // 拿到ID后立刻取消监听,避免重复触发 subscribe() container_signup.querySelector(".error").innerHTML = ''; } }) }).catch(err => { container_signup.querySelector(".error").innerHTML = err.message; }); } else { container_signup.querySelector(".error").innerHTML = "Please add all the required informations." }
可选优化
你现有subscribe函数中的onSnapshot监听器没有做取消处理,极端情况下可能被多次触发,可以在拿到结账URL跳转前加上取消监听的逻辑:
async function subscribe() { const docRef = await db .collection('collection-users') .doc(firebase.auth().currentUser.uid) .collection('checkout_sessions') .add({ price: 'price_id', success_url: 'https://mywebsite.com', cancel_url: 'https://mywebsite.com', }); // 保存监听器引用,后续取消 const unsubscribeSnapshot = docRef.onSnapshot((snap) => { const { error, url } = snap.data(); if (error) { unsubscribeSnapshot() alert(`An error occured: ${error.message}`); } if (url) { unsubscribeSnapshot() // 拿到URL后先取消监听再跳转 window.location.assign(url); } }); }
内容的提问来源于stack exchange,提问作者Max Trautwein
相关产品推荐
相关产品推荐

