Cloud Function添加额外用户信息创建完整Stripe Customer的实现问题
问题修复方案
核心错误原因
- 云函数取值逻辑错误:
context.auth.uid是字符串类型的用户唯一ID,不是包含用户信息的对象,你当前写的context.auth.uid.fullname必然返回undefined - 传参类型错误:前端调用云函数时传入的
profileImage是UIImage对象,无法直接被云函数解析,应该传入你已经上传到Storage生成的图片URL字符串 - Stripe接口参数不匹配:Stripe创建客户的原生接口不支持
fullname/username/profileImage三个自定义字段,自定义参数需要放在metadata字段下才能正常存储 - 数据库写入逻辑冲突:云函数里用
set写入customers节点会直接覆盖你之前在AuthService中写入的同uid用户数据,导致其他字段丢失
修复步骤
1. 调整AuthService逻辑,把生成的图片URL回传给注册回调
把你的AuthService代码修改为回调时返回图片URL:
static func createCustomer(credentials: CustomerCredentials, completion: @escaping(Error?, DatabaseReference?, String?) -> Void) { guard let imageData = credentials.profileImage.jpegData(compressionQuality: 0.3) else { return } let filename = NSUUID().uuidString let storageRef = STORAGE_REF.reference(withPath: "/customer_profile_images/\(filename)") storageRef.putData(imageData, metadata: nil) { (meta, error) in if let error = error { debugPrint(error.localizedDescription) completion(error, nil, nil) return } storageRef.downloadURL { (url, error) in guard let profileImageUrl = url?.absoluteString else { completion(error, nil, nil) return } Auth.auth().createUser(withEmail: credentials.email, password: credentials.password) { (result, error) in if let error = error { debugPrint(error.localizedDescription) completion(error, nil, nil) return } guard let uid = result?.user.uid else { return } let values = ["email" : credentials.email, "fullname" : credentials.fullname, "username" : credentials.username, "uid" : uid, "profileImageUrl" : profileImageUrl] as [String : Any] CustomerDataService.saveCustomerData(uid: uid, fullname: credentials.fullname, email: credentials.email, username: credentials.username, profileImagUrl: profileImageUrl) REF_CUSTOMERS.child(uid).setValue(values) { error, ref in completion(error, ref, profileImageUrl) } } } } }
2. 修改注册逻辑的云函数调用参数,传入图片URL而非UIImage
修改你的handleCreateAccount中的云函数调用部分:
AuthService.createCustomer(credentials: credentials) { (error, ref, profileImageUrl) in if let error = error { Auth.auth().handleFireAuthError(error: error, vc: self) self.showLoader(false) return } guard let profileImageUrl = profileImageUrl else { self.showLoader(false) return } Functions.functions().httpsCallable("createStripeCustomer").call([ "email": credentials.email, "fullname": credentials.fullname, "username": credentials.username, "profileImage": profileImageUrl ]) { result, error in if let error = error { Auth.auth().handleFireAuthError(error: error, vc: self) self.showLoader(false) return } } // 原有跳转逻辑保留 self.showLoader(false) guard let window = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return } guard let tab = window.rootViewController as? MainTabController else { return } tab.setupNavigationControllers() self.handleDismissal() }
3. 修复云函数的取值和Stripe参数逻辑
修改后的云函数代码如下:
exports.createStripeCustomer = functions.https.onCall( async (data, context) => { // 验证登录状态 const uid = context.auth?.uid if (!uid) { console.log('Illegal access attempt due to unauthenticated attempt.') throw new functions.https.HttpsError('internal', 'Illegal access attempt') } // 所有参数从前端传入的data中取 const email = data.email const fullname = data.fullname const username = data.username const profileImage = data.profileImage return stripe.customers.create({ email : email, // 自定义参数放入metadata metadata: { fullname : fullname, username : username, profileImage : profileImage } }).then( customer => { return customer.id }).then( customerId => { // 用update代替set,避免覆盖原有用户数据 return admin.database().ref("customers").child(uid).update({ stripeId: customerId }) }).catch( err => { console.error(err) throw new functions.https.HttpsError('internal', 'Unable to create Stripe customer.') }) })
额外说明
不需要拆分注册流程为两步,按照上述修改后,注册时就可以一次性完成用户创建、头像上传、Stripe客户生成、数据同步的全流程,不会出现字段丢失的问题。
内容的提问来源于stack exchange,提问作者Zachary Smouse
相关产品推荐
相关产品推荐

