Flutter中如何获取Firebase Realtime Database规则触发的报错
解决方案
你无法捕获规则报错主要是三个核心问题:
- 匿名用户分支的数据库写入逻辑没有包裹异常捕获逻辑
- 异步方法
updateDisplayName没有加await,执行时序错误 - 异常捕获的类型匹配错误,新版FlutterFire Realtime Database抛出的异常为
FirebaseException而非旧的DatabaseError
修复步骤
- 给匿名用户分支的逻辑也加上try-catch包裹
- 给所有异步的用户更新、数据库写入方法加上
await修饰 - 调整异常捕获的类型优先级,优先捕获
FirebaseException - 补全函数的返回值,符合声明的返回类型
修复后的完整代码
import 'package:firebase_core/firebase_core.dart' show FirebaseException; // 需提前导入对应头文件 Future<User?> addUsernameToDatabase(String? username) async { final user = FirebaseAuth.instance.currentUser; if(user == null || username == null) return null; setLoading(true); try { // 异步方法必须加await等待执行完成 await user.updateDisplayName(username); final uid = user.uid; if(user.isAnonymous) { print("Guest user"); await _dbRef.child('usernames').child(username).set(uid); } else { await _dbRef.child('usernames').child(username).set(uid); } setLoading(false); return user; } on FirebaseException catch (error) { // 规则拦截的报错会在这里捕获,错误code为permission-denied print("数据库规则拦截错误:${error.code},信息:${error.message}"); setLoading(false); return null; } on PlatformException catch (error) { print("平台错误:${error.toString()}"); setLoading(false); return null; } catch (error) { print("未知错误:${error.toString()}"); setLoading(false); return null; } }
额外补充
你当前贴出的数据库规则仅校验了/users/$uid/username节点的写入合法性,并没有对/usernames节点的写入做限制。如果需要保证/usernames节点下的用户名全局唯一,需要补充对应规则:
{ "rules": { "usernames": { "$username": { ".write": "!data.exists() || data.val() === auth.uid" } }, // 剩下的原有规则保持不变 ".read": true, ".write": true, "users":{ "$uid": { ".write": "auth !== null && auth.uid === $uid", ".read": "auth !== null && auth.provider === 'password'", "username": { ".validate": "!root.child('usernames').child(newData.val()).exists() || root.child('usernames').child(newData.val()).val() == $uid" } } } } }
修复完成后规则触发的权限拒绝错误就会被FirebaseException正常捕获,你可以根据error.code == 'permission-denied'判断是用户名重复导致的拦截,给用户弹出对应提示即可。
内容的提问来源于stack exchange,提问作者Nurhan Abulcai
相关产品推荐
相关产品推荐

