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

在onPressed函数中调用docRef.snapshots()报错的原因及解决方法

问题:Firestore读取"url"字段时抛出Bad state异常

我为ElevatedButton编写了如下代码片段:

onPressed: () async {
  var docRef = await context
      .read<FirestoreRepository>()
      .firestore
      .collection('users')
      .doc(userData.selfRef.id)
      .collection('checkout_sessions')
      .add({
    'price': pricePlans.first.selfRef.id,
    'success_url': 'https://success.com',
    'cancel_url': 'https://cancel.com'
  });
  debugPrint('doc added');
  docRef
      .snapshots()
      .listen((ds) {
    if (ds.exists) {
      var url = ds.get('url'); 
      if (context.mounted) {
        Navigator.push(context, MaterialPageRoute(builder: (_) {
          return CheckoutPage(url: url);
        }));
  // 注:原代码存在语法错误,缺少闭合的大括号与括号
});

调用docRef.snapshots()时触发未捕获异常断点,报错信息:

Bad state: field "url" does not exist within the DocumentSnapshotPlatform

我的模型文件代码如下:

class CheckoutSessionModel extends Equatable {
  final String model;
  final String sessionId;
  final String url;
  final String price;
  const CheckoutSessionModel({
    required this.model,
    required this.sessionId,
    required this.url,
    required this.price,
  });

  factory CheckoutSessionModel.fromSnapshot(
      DocumentSnapshot<Map<String, dynamic>> snapshot) {
    final data = snapshot.data()!;

    return CheckoutSessionModel(
        model: data['mode'] as String? ?? '',
        sessionId: data['sessionId'] as String? ?? '',
        url: data['url'] as String? ?? '',
        price: data['price'] as String? ?? '');
  }

  @override
  List<Object> get props => [model, sessionId, url, price];
}

报错原因

  1. 初始文档无"url"字段:通过add()写入Firestore的初始文档仅包含price、success_url、cancel_url三个字段,url字段是后续由第三方服务(如Stripe支付扩展)异步生成写入的。而docRef.snapshots()会立即触发第一次快照,此时文档还未生成url字段。
  2. ds.get()的特性:Firestore的DocumentSnapshot.get()方法在目标字段不存在时会直接抛出Bad state异常,代码中未做任何判空处理,导致触发断点。

修复方案

方案1:使用可选访问避免异常

直接通过data()获取文档数据后做可选访问,字段不存在时返回null,判断非空后再执行跳转:

docRef.snapshots().listen((ds) {
  if (ds.exists) {
    // 用可选访问符,字段不存在时返回null
    final url = ds.data()?['url'];
    if (url != null && context.mounted) {
      Navigator.push(context, MaterialPageRoute(builder: (_) {
        return CheckoutPage(url: url);
      }));
    }
  }
});

方案2:复用现有模型类的处理逻辑

CheckoutSessionModel已经通过data['url'] as String? ?? ''处理了字段不存在的情况,直接用模型类解析快照,再判断url非空后跳转:

docRef.snapshots().listen((ds) {
  if (ds.exists) {
    final session = CheckoutSessionModel.fromSnapshot(ds);
    // 模型中字段不存在时返回空字符串,判断非空后跳转
    if (session.url.isNotEmpty && context.mounted) {
      Navigator.push(context, MaterialPageRoute(builder: (_) {
        return CheckoutPage(url: session.url);
      }));
    }
  }
});

方案3:使用get()的默认值参数

Firestore的get()方法支持传入defaultValue参数,字段不存在时返回指定默认值,避免抛出异常:

docRef.snapshots().listen((ds) {
  if (ds.exists) {
    // 字段不存在时返回null
    final url = ds.get('url', defaultValue: null);
    if (url != null && context.mounted) {
      Navigator.push(context, MaterialPageRoute(builder: (_) {
        return CheckoutPage(url: url);
      }));
    }
  }
});

另外注意:原代码的listen回调函数存在语法错误,缺少闭合的大括号和括号,修复时需要补上,否则无法正常编译。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:06:09