为何首次点击注册按钮时文档未成功存入Firestore数据库?
问题根因与修复方案
核心根因
你遇到的首次写入失败问题是两个Firebase开发的高频坑共同导致的:
- 注册成功后获取UID的方式错误:
registerWithEmailAndPassword执行成功返回时,FirebaseAuth.instance.currentUser并不保证已经完成状态同步,首次调用大概率返回null,你用!强转触发的空异常被UserDataService.createUserRecord中的catch捕获,直接返回错误信息,写入逻辑终止但你可能没注意到报错提示。 - 写入后立刻登出打断同步:如果你开启了Firestore默认的离线持久化,
await set会在本地缓存写入完成后立刻返回,不等服务器同步完成。此时你立刻调用signOut,后台同步请求会携带已失效的未登录态,被安全规则拦截导致写入服务器失败。
修复方案
1. 修改注册方法透传UID
修改registerWithEmailAndPassword的返回值,不要只返回错误字符串,直接返回Future<UserCredential?>,注册成功时返回接口返回的凭证,失败时返回null/抛出异常,从凭证中直接拿UID,不要走currentUser获取:
// 改造后的注册方法示例 Future<UserCredential?> registerWithEmailAndPassword(String name, String email, String password) async { try { final credential = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: email, password: password ); return credential; } catch(e) { debugPrint(e.toString()); return null; } }
2. 调整注册调用逻辑,用返回的UID写入Firestore
register(String? nameOfUser, String? emailOfUser, String? passwordOfUser, PropertyManagement? pm, BuildContext context) async { final credential = await widget.authService.registerWithEmailAndPassword( nameOfUser!.trim(), emailOfUser!.trim(), passwordOfUser! ); // 注册成功,直接从返回的凭证拿UID if (credential != null && credential.user != null) { final uid = credential.user!.uid; String? errorMessage = await UserDataService.createUserRecord( uid, nameOfUser, emailOfUser); if (errorMessage == createdRecordMessage) { errorMessage = await PropertyManagementDataService.createDatabaseRecord( pm!, credential.user!); if (errorMessage == createdRecordMessage) { // 等待Firestore写入同步到服务器再登出,避免同步请求被拦截 await Future.delayed(const Duration(milliseconds: 500)); widget.authService.signOut(); NavigationService.navigateToHome(context); return; } } } SnackbarService.displayWithTitleAndMessage(context, 'Error:', errorMessage); }
可选优化
如果需要确保写入服务器成功后再执行后续操作,可以在调用set时指定SetOptions并监听写入完成的回调,或者临时关闭该写入操作的离线缓存。
内容的提问来源于stack exchange,提问作者Freddy Straub
相关产品推荐
相关产品推荐

