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

Flutter中如何通过Dio动态指定请求返回的数据模型?

问题描述

在进行网络数据交互时,如何确保dio返回的响应数据符合特定的数据模型?

例如,所有响应内容均为application/JSON类型,并符合以下规则:

  • 字段code为0到1000之间的整数。
  • 字段message为可选提示文本,可能为null。
  • 字段timestamp为当前时间的秒级时间戳。
  • 字段data为可选数据,可为任意类型,可能为null。

因此,定义了如下模型:

class ResponseModel<T> {
  late final int code;
  late final int timestamp;
  late final String? message;
  late final T? data;
}

通过dio获取的所有响应数据都存储在_InternalLinkedHashMap类型的Map中,无法通过如下方法签名指定返回类型来完成转换:

Future<Response<ResponseModel>> request() {
    // 使用`dio`访问网络数据并返回
}

那么,如何在dio中将响应数据存储到ResponseModel模型中?

已尝试方案:查阅相关文档后,了解到可以通过命名构造函数进行数据转换,但由于该模型包含泛型类型,无法编写标准的转换函数。

相关代码:

class ResponseModel<T> {
  /*
    部分字段
   */

  ResponseModel.fromJson(Map<String, dynamic> json) {
    code = json['code'] as int;
    timestamp = json['timestamp'] as int;
    if (null != json['message']) {
      message = json['message'] as String;
    }
    // 如何转换data?
  }
}

解决方案

1. 改造泛型模型的构造函数

给ResponseModel的命名构造函数添加数据转换回调,用来处理泛型data的解析,不同接口可传入对应转换逻辑:

class ResponseModel<T> {
  final int code;
  final int timestamp;
  final String? message;
  final T? data;

  // 用初始化列表替代late,避免空安全隐患
  ResponseModel({
    required this.code,
    required this.timestamp,
    this.message,
    this.data,
  });

  // 添加data解析回调参数
  ResponseModel.fromJson(
    Map<String, dynamic> json,
    T? Function(dynamic)? dataParser,
  ) : code = json['code'] as int,
        timestamp = json['timestamp'] as int,
        message = json['message'] as String?,
        data = dataParser != null ? dataParser(json['data']) : json['data'] as T?;
}

2. 在Dio请求中使用模型

发起请求时,传入对应data的解析函数即可:

// 示例:假设data是User类型
class User {
  final String name;
  final int age;

  User.fromJson(Map<String, dynamic> json) : name = json['name'], age = json['age'];
}

Future<ResponseModel<User>> getUser() async {
  final response = await Dio().get('your-api-url');
  return ResponseModel<User>.fromJson(
    response.data,
    (data) => data != null ? User.fromJson(data) : null,
  );
}

// 如果data是基础类型(String/int等),可直接省略解析函数
Future<ResponseModel<String>> getStringData() async {
  final response = await Dio().get('another-api-url');
  return ResponseModel<String>.fromJson(response.data, null);
}

3. 全局拦截器统一处理(可选)

如果所有接口都要使用该模型,可通过Dio拦截器统一解析,减少重复代码:

class ResponseInterceptor extends Interceptor {
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    // 先统一校验code、timestamp等字段合法性
    if (response.data is Map<String, dynamic>) {
      // 简单示例:若无需强类型解析data,直接包装
      final model = ResponseModel<dynamic>.fromJson(response.data, null);
      response.data = model;
    }
    handler.next(response);
  }
}

// 初始化Dio时添加拦截器
final dio = Dio()..interceptors.add(ResponseInterceptor());

注意事项

  • 优先使用初始化列表替代late final,避免空安全问题。
  • 解析data时要处理null场景,防止类型转换异常。
  • 若需复杂泛型解析,可结合json_serializable库的JsonConverter实现更灵活的类型转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 05:50:37