You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法将StripeID保存到Firestore集合文档的问题排查

问题:Firestore无法保存Stripe客户ID

由于需要更强的查询能力,我正将数据从Firebase Realtime Database迁移到Firestore,但在将客户的stripeID保存到其集合文档时遇到问题。我的Cloud Function运行正常,Stripe已成功创建客户,但stripeID并未被写入对应的Firestore集合文档。请问需要如何修改才能让集合文档正确存储stripeID?

问题现象

Firestore文档缺少stripeId字段
Stripe已成功创建客户

客户模型

struct Customer {
    
    let uid: String
    let stripeId: String
    let fullname: String
    let email: String
    let username: String
    let profileImageUrl: String
    
    init(dictionary: [String : Any]) {
        self.uid = dictionary["uid"] as? String ?? ""
        self.stripeId = dictionary["stripeId"] as? String ?? ""
        self.fullname = dictionary["fullname"] as? String ?? ""
        self.email = dictionary["email"] as? String ?? ""
        self.username = dictionary["username"] as? String ?? ""
        self.profileImageUrl = dictionary["profileImageUrl"] as? String ?? ""
    }
    
}

AuthServices

struct CustomerCredentials {
    let email: String
    let password: String
    let fullname: String
    let username: String
    let profileImage: UIImage
}

static func createCustomer(credentials: CustomerCredentials, completion: CollectionCompletion) {

    Auth.auth().createUser(withEmail: credentials.email, password: credentials.password) { result, error in
                if let error = error {
                    debugPrint(error.localizedDescription)
                    return
                }
                    
                guard let uid = result?.user.uid else { return }
                    
                let values = ["uid" : uid,
                              "email" : credentials.email,
                              "fullname" : credentials.fullname,
                              "username" : credentials.username,
                              "profileImageUrl" : profileImageUrl]
                    
                REF_CUSTOMERS.document(uid).setData(values, completion: completion)
            }
    }

}

注册控制器(RegistrationController)

@objc func handleCreateAccount() {

    let credentials = CustomerCredentials(email: email, password: password, fullname: fullname,
                                          username: username, profileImage: profileImage)
        
    AuthService.createCustomer(credentials: credentials) { error in
        if let error = error {
            Auth.auth().handleFireAuthError(error: error, vc: self)
            self.showLoader(false)
            return
        }
            
        Functions.functions().httpsCallable("createStripeCustomer").call(["email" : email]) { result, error in
            if let error = error {
                debugPrint(error.localizedDescription)
                return
            }
        }

    }

}

解决方案

问题核心是云函数未将Stripe返回的客户ID写入Firestore,且客户端未处理云函数返回结果做补全更新。

1. 修改云函数createStripeCustomer

确保创建Stripe客户后,直接更新对应Firestore文档:

exports.createStripeCustomer = functions.https.onCall(async (data, context) => {
  // 校验用户登录状态
  if (!context.auth) {
    throw new functions.https.HttpsError('unauthenticated', '用户未登录');
  }
  
  const email = data.email;
  const uid = context.auth.uid;
  
  // 创建Stripe客户
  const customer = await stripe.customers.create({ email: email });
  
  // 写入Firestore文档
  await admin.firestore().collection('customers').doc(uid).update({
    stripeId: customer.id
  });
  
  // 返回stripeID给客户端(可选,用于本地逻辑校验)
  return { stripeId: customer.id };
});

2. 优化客户端注册控制器

在云函数调用成功后,处理返回的stripeID并做本地更新(双重保险):

@objc func handleCreateAccount() {

    let credentials = CustomerCredentials(email: email, password: password, fullname: fullname,
                                          username: username, profileImage: profileImage)
        
    AuthService.createCustomer(credentials: credentials) { error in
        if let error = error {
            Auth.auth().handleFireAuthError(error: error, vc: self)
            self.showLoader(false)
            return
        }
            
        guard let uid = Auth.auth().currentUser?.uid else { 
            self.showLoader(false)
            return 
        }
            
        Functions.functions().httpsCallable("createStripeCustomer").call(["email" : email]) { result, error in
            if let error = error {
                debugPrint(error.localizedDescription)
                self.showLoader(false)
                return
            }
            
            // 从云函数返回结果中提取stripeID
            if let data = result?.data as? [String: Any], let stripeId = data["stripeId"] as? String {
                // 更新Firestore文档
                REF_CUSTOMERS.document(uid).updateData(["stripeId": stripeId]) { updateError in
                    if let updateError = updateError {
                        debugPrint(updateError.localizedDescription)
                    }
                    self.showLoader(false)
                    // 执行后续页面跳转等逻辑
                }
            } else {
                self.showLoader(false)
                debugPrint("无法获取Stripe客户ID")
            }
        }
    }
}

3. 校验Firestore安全规则

确保云函数和用户拥有对应文档的更新权限:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /customers/{uid} {
      allow read, update: if request.auth != null && request.auth.uid == uid;
      allow create: if request.auth != null;
      // 允许云服务账号更新文档
      allow update: if request.auth.token.firebase.sign_in_provider == "service_account";
    }
  }
}

内容的提问来源于stack exchange,提问作者Zachary Smouse

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 10:30:53