如何使用 Flutter 防御性地从 Firestore 请求数据

Posted

技术标签:

【中文标题】如何使用 Flutter 防御性地从 Firestore 请求数据【英文标题】:How to request data from Firestore defensively with Flutter 【发布时间】:2021-11-22 02:36:59 【问题描述】:

由于 Firestore 是一个 NoSQL 数据库并且没有严格的类型规则和定义的文档结构,我考虑在我的 Flutter 应用中处理损坏的数据。

如果你想知道我为什么要防御性请求,即使它不是第三方 API -> 我可以想到我的应用程序由于数据损坏而崩溃的三个原因:

我通过 Firebase 控制台添加了错误的数据,例如将类型 string 用于应该类型为 number 的字段(反复发生)。 我的应用程序中的一个错误将损坏的数据添加到 Firestore。 用户安装了我的应用的旧版本,无法处理新的 Firestore 数据结构。

我的要求:当请求来自 Firestore 的损坏数据时,应用程序不应崩溃,但应报告损坏的数据,以便可以在 Firestore a.s.a.p. 中修复数据。

【问题讨论】:

【参考方案1】:

您如何看待以下方法?

假设我们有一个模型Movie

Movie 
  final String title;
  final int releaseYear;

  Movie(required this.title, required this.releaseYear);

  Movie.from(Map<String, dynamic> data)
      : title = data['title'],
        releaseYear = data['release_year'];

命名构造函数from 解析来自DocumentSnapshot.data() 的文档数据并返回我们的模型。只要数据具有String 类型的字段titleint 类型的字段release_year(Firestore 中的number),此方法就可以正常工作。

假设实际数据中缺少字段release_year。这将使请求崩溃。因此,当前用户无法对相应电影执行任何操作,而我作为开发人员不会注意到,因为它在用户的设备上静默发生。

要解决第一个问题,我们可以使用带有后备数据的防御性解析,如下所示:data['release_year'] ?? -1。没有发生崩溃,但我作为开发人员仍然没有注意到并且无法修复数据。

要解决此问题,我们还可以使用 Firebase Crashlytics。唯一的问题是,如果我们使用防御性解析来防止崩溃,则不会将任何日志发送到 Firebase。这就是我想出这个解决方案的原因:

final snapshot = await FirebaseFirestore.instance.collection('movies').doc('123').get();
try 
  return Movie.from(snapshot.data()!);
 catch (e) 
  await FirebaseCrashlytics.instance
      .recordError(e, e.stackTrace(), reason: 'data of movie $snapshot.id is corrupt');
  return Movie.fromCorrupt(snapshot.data()!);

首先,应用程序尝试在没有任何回退机制的情况下解析文档数据。如果数据损坏,则会引发并捕获异常。在 catch 块中,错误被发送到 Firebase,然后调用防御性解析构造函数fromCorrupt 让用户继续使用剩余的数据在应用程序中。在fromCorrupt 中,每个字段在用于创建模型Movie 之前都检查了null 和类型。如果值为 null 或类型错误,则使用备用值。

你觉得我的方法怎么样?我是否过度设计? ?

【讨论】:

以上是关于如何使用 Flutter 防御性地从 Firestore 请求数据的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 上传列表到 Google Firestore

如何无限制地从 Cloudinary API 获取所有图像或如何使用 next_cursor?

致命错误:集成 firestore 后在 Flutter iOS 构建中找不到“openssl/x509.h”文件

Flutter 混合开发基础

Android 集成Flutter

UI2CODE: 自动将 UI 框架转换为 Flutter 代码