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

使用DetailsResponseModel.fromJson解析JSON无返回的问题求助

Dart模型解析JSON失败的原因排查与解决

问题背景

调用DetailsResponseModel.fromJson(response)无法解析出有效结果,但直接用dynamic类型可以正常获取返回数据。该Model由QuickType生成,已尝试多种调整仍未解决。调试确认GET请求能正常返回目标JSON数据,也曾针对datetime字段排查,问题已持续3天。

相关代码与返回数据

DetailsResponseModel代码

// To parse this JSON data, do
//
//     final detailsResponseModel = detailsResponseModelFromJson(jsonString);

import 'dart:convert';

DetailsResponseModel detailsResponseModelFromJson(String str) => DetailsResponseModel.fromJson(json.decode(str));

String detailsResponseModelToJson(DetailsResponseModel data) => json.encode(data.toJson());

class DetailsResponseModel {
    DetailsResponseModel({
        required this.pkId,
        required this.status,
        required this.dateBegin,
        this.dateEnd,
        required this.usersTotal,
        required this.usersActive,
        required this.moneyTotal,
        required this.moneyRest,
        required this.incomeRate,
        required this.chart,
    });

    int pkId;
    String status;
    DateTime dateBegin;
    DateTime? dateEnd;
    int usersTotal;
    int usersActive;
    double moneyTotal;
    int moneyRest;
    double incomeRate;
    List<Chart> chart;

    factory DetailsResponseModel.fromJson(Map<String, dynamic> json) => DetailsResponseModel(
        pkId: json["pk_id"],
        status: json["status"],
        dateBegin: DateTime.parse(json["date_begin"]),
        dateEnd: json["date_end"] == null ? null : DateTime.parse(json["date_end"]),
        usersTotal: json["users_total"],
        usersActive: json["users_active"],
        moneyTotal: json["money_total"]?.toDouble(),
        moneyRest: json["money_rest"],
        incomeRate: json["income_rate"]?.toDouble(),
        chart: List<Chart>.from(json["chart"].map((x) => Chart.fromJson(x))),
    );

    Map<String, dynamic> toJson() => {
        "pk_id": pkId,
        "status": status,
        "date_begin": dateBegin.toIso8601String(),
        "date_end": dateEnd?.toIso8601String(),
        "users_total": usersTotal,
        "users_active": usersActive,
        "money_total": moneyTotal,
        "money_rest": moneyRest,
        "income_rate": incomeRate,
        "chart": List<dynamic>.from(chart.map((x) => x.toJson())),
    };
}

class Chart {
    Chart({
        required this.datetime,
        required this.value,
    });

    DateTime datetime;
    double value;

    factory Chart.fromJson(Map<String, dynamic> json) => Chart(
        datetime: DateTime.parse(json["datetime"]),
        value: json["value"]?.toDouble(),
    );

    Map<String, dynamic> toJson() => {
        "datetime": datetime.toIso8601String(),
        "value": value,
    };
}

返回的JSON数据

{
    "pk_id": 5,
    "status": "ACTIVE",
    "date_begin": "2023-03-25T00:00:00Z",
    "date_end": null,
    "users_total": 6,
    "users_active": 6,
    "money_total": 15.0,
    "money_rest": 13.0,
    "income_rate": 1.5,
    "chart": [
        {
            "datetime": "2023-04-12T16:43:45Z",
            "value": 7.0
        },
        {
            "datetime": "2023-04-04T16:44:27Z",
            "value": 3.0
        }
    ]
}

DataSource代码

import 'dart:convert';
import 'package:injectable/injectable.dart';

import '../../../core/shared/http.dart';
import '../../models/response/details_by_id_response_model.dart';

abstract class DetailsByIdRemoteDataSource {
  Future<DetailsResponseModel> getDetailsById({required int scenario});

}

@LazySingleton(as: DetailsByIdRemoteDataSource)
class DetailsByIdRemoteDataSourceImpl implements DetailsByIdRemoteDataSource {
  final Http http;
  const DetailsByIdRemoteDataSourceImpl({
    required this.http,
  });

  @override
  Future<DetailsResponseModel> getDetailsById(
      {required int scenario}) async {
    final response = await http.get(
      '/scenarioinfo?scenario_id=$scenario&pk_id=3',
    );

    return DetailsResponseModel.fromJson(response);
  }
}

核心原因分析

  1. 类型不匹配(最可能的问题)
    返回的JSON中money_rest字段值为13.0(double类型),但Model里moneyRest被定义为int类型。Dart不允许将double直接赋值给int变量,解析时会抛出类型转换异常,导致整个Model实例化失败。而dynamic类型会自动隐式转换,所以能正常取值。

  2. Http返回值类型不确定
    需确认自定义Http工具类的get方法返回的是已解码的Map<String, dynamic>还是原始JSON字符串:

    • 如果是原始字符串,直接传入fromJson会报错,需要先调用json.decode()转换为Map再解析。
    • 若返回的是Map,问题就集中在类型不匹配上。
  3. 异常未被捕获
    当前代码没有异常捕获逻辑,解析失败时无法看到具体错误信息,导致排查困难。

解决方案

1. 修正类型不匹配问题

有两种处理方式:

  • 方式一:修改Model字段类型
    将moneyRest的类型从int改为double:

    double moneyRest;
    

    同时更新构造函数和toJson方法对应的字段类型。

  • 方式二:显式转换类型
    在fromJson工厂方法中,将money_rest的值转换为int:

    moneyRest: json["money_rest"].toInt(),
    

2. 验证Http返回值类型

检查Http类的get方法实现,如果返回的是String,修改DataSource代码:

@override
Future<DetailsResponseModel> getDetailsById({required int scenario}) async {
  final responseStr = await http.get(
    '/scenarioinfo?scenario_id=$scenario&pk_id=3',
  );
  final response = json.decode(responseStr) as Map<String, dynamic>;
  return DetailsResponseModel.fromJson(response);
}

3. 添加异常捕获方便调试

在解析代码中加入try-catch,打印错误信息:

@override
Future<DetailsResponseModel> getDetailsById({required int scenario}) async {
  final response = await http.get(
    '/scenarioinfo?scenario_id=$scenario&pk_id=3',
  );
  try {
    return DetailsResponseModel.fromJson(response);
  } catch (e, stackTrace) {
    print('JSON解析错误详情: $e');
    print('调用栈: $stackTrace');
    rethrow; // 重新抛出异常不影响上层逻辑
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 09:57:19