[Flutter3] 记录Dio的简单封装(一)

发布于:2024-04-26 ⋅ 阅读:(27) ⋅ 点赞:(0)

效果

请求成功/失败/异常的日志输出效果
成功:
在这里插入图片描述
失败:500
在这里插入图片描述
失败:404
在这里插入图片描述
网络异常:
在这里插入图片描述

使用

举个使用的例子, 在调用 DioManager的时候, 直接通过返回值的状态, 来处理各个情况,不用在 try{}catch{}里面各写一遍处理逻辑,

比如上图,就是直接调用的封装的API

      ResponseEntity res = await DioManager().requestGet(HttpApi.user_record, param: {
        "openid": "okqbz5K-4UoymmukFtxyQAyImKm0",
        "uid": "88030",
        "subject": '20',
        "unionid": "ofJJv6M45ChFhuUZyVaLXwt07M4g",
      });
      res.toLog();

直接同步获取了请求的结果,通过 ResponseEntity 来处理本次请求的各项情况(如上4图)

ResponseEntity类

提供了 泛型T的data属性,
提供了 tag, 用于处理请求的不同情况
提供了 toString/ toLog函数 , 用于查看请求/返回/状态码/请求参数等


class ResponseEntity<T> {
  /// 常规的response.data的返回字段
  late String? msg;
  late int? code;
  T? data;

  /// response.data中,自定以追加的一些字段(方便日志查看)
  late int? tag; // 业务tag  0=>通信OK+业务未跑通 1=>通信OK+业务跑通  2=>通信失败(各类原因...) 9=>解析/socket等异常
  late String? method; // 请求的 method
  late String? baseUrl; // 请求的host地址 - 方便打印日子产看环境
  late String? path; // 请求地址
  late String? desc; // 自定义的报文描述-便于判断请求情况
  late Map<String, dynamic>? queryParameters; // 请求的参数

  ResponseEntity(
      this.code, this.msg, this.data, this.tag, this.method, this.baseUrl, this.path, this.desc, this.queryParameters);

  ResponseEntity.initFromJson(Map<String, dynamic> jsonMap) {
    code = jsonMap.containsKey(ConstantUtil.code) ? jsonMap[ConstantUtil.code] as int? : 0;
    msg = jsonMap.containsKey(ConstantUtil.msg) ? jsonMap[ConstantUtil.msg] as String? : "";
    // 存在data
    if (jsonMap.containsKey(ConstantUtil.data)) {
      data = jsonMap[ConstantUtil.data] as T;
    }

    /// response自定以追加的一些字段处理
    tag = jsonMap.containsKey(ConstantUtil.tag) ? jsonMap[ConstantUtil.tag] : 9;
    method = jsonMap.containsKey(ConstantUtil.method) ? jsonMap[ConstantUtil.method] : "";
    baseUrl = jsonMap.containsKey(ConstantUtil.baseUrl) ? jsonMap[ConstantUtil.baseUrl] : "";
    path = jsonMap.containsKey(ConstantUtil.path) ? jsonMap[ConstantUtil.path] : "";
    queryParameters = jsonMap.containsKey(ConstantUtil.queryParameters) ? jsonMap[ConstantUtil.queryParameters] : null;
    desc = jsonMap.containsKey(ConstantUtil.desc) ? jsonMap[ConstantUtil.desc] : "";
  }

  /// 手动重写toString 方法,方便查看日志
  
  String toString() {
    var _code = "code:$code\n";
    var _msg = "msg:$msg\n";
    var _data = json.encode(data).toString();
    var _dataString = "data:$_data\n";
    var _tag = "tag:$tag\n";
    var _method = "method:$method\n";
    var _baseUrl = "baseUrl:$baseUrl\n";
    var _path = "path:$path\n";
    var _desc = "path:$desc\n";
    var _queryParameters = jsonEncode(queryParameters);
    var _queryParametersString = "queryParameters:$_queryParameters\n";

    return _code + _msg + _dataString + _tag + _method + _baseUrl + _path + _desc + _queryParametersString;
  }

  /// 提供自带的打印函数
  void toLog() {
    LoggerUtil().d(toString());
  }
}

DioManager封装

对DioManager进行单例模式处理

  /// dio管理类的单例的实现 --------------------------------------------------
  // 定义私有管理对象 _singleton
  static final DioManager _singleton = DioManager._();

  // 私有对象构造实现
  DioManager._() {
    // dio初始化 - 配置全局options - 具体事项先省略
  }

  // 声明并完成初始化的私有变量(_singleton),
  // 通过 DioManager的工厂函数(factory关键字) ,进行单例模式返回
  factory DioManager() => _singleton;

提供_request通用方法

 /// request 通用处理函数 -----------------------------------------------------------
  /// get 对应的是 queryParam
  /// post 对应的是 data
  /// 通过 对 try/catch 的处理, 均异步返回有效的 BaseResponseEntity<T> 实例,
  /// 外部调用时候,仅获取数据是, 可以不必包裹 try/catch,
  Future<ResponseEntity<T>> _request<T>(
    String method,
    String apiPath, {
    Map<String, dynamic>? param,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    try {
      // 通用请求
      Response<dynamic> response = await _dio.request(apiPath,
          data: param, queryParameters: param, cancelToken: cancelToken, options: _loadOptions(method, options));
      // 通过 _onResponse()函数转换response
      // 自定义返回的data内容, 除了原有的 code/msg/data信息, 新增desc/tag等返回数据
      response = _onResponse(response);
      return ResponseEntity<T>.initFromJson(response.data);
    } on DioException catch (err) {
      // 通过对DioException的解析,返回自定义的BaseResponseEntity实例
      return _onDioException(err) as ResponseEntity<T>;
    }

  }

_onResponse / _onDioException 的设计

根据Request的情况, 把交互场景分为了四类

1&2: statusCode == 200 , 再区分业务code是否OK
3: statusCode !==200, 可能是 404 /500 等情况
4: 断网等异常情况

其中 1&2&3, 都是通过_onResponse处理
4通过_onDioException处理, 这里的catch不再直接抛出, 用ResponseEntity来统一做返回格式处理
(DioException)

Response的处理

class ResponseEntity<T> {
  /// 常规的response.data的返回字段
  late String? msg;
  late int? code;
  T? data;

  /// response.data中,自定以追加的一些字段(方便日志查看)
  late int? tag; // 业务tag  0=>通信OK+业务未跑通 1=>通信OK+业务跑通  2=>通信失败(各类原因...) 9=>解析/socket等异常
  late String? method; // 请求的 method
  late String? baseUrl; // 请求的host地址 - 方便打印日子产看环境
  late String? path; // 请求地址
  late String? desc; // 自定义的报文描述-便于判断请求情况
  late Map<String, dynamic>? queryParameters; // 请求的参数

  ResponseEntity(
      this.code, this.msg, this.data, this.tag, this.method, this.baseUrl, this.path, this.desc, this.queryParameters);

  ResponseEntity.initFromJson(Map<String, dynamic> jsonMap) {
    code = jsonMap.containsKey(ConstantUtil.code) ? jsonMap[ConstantUtil.code] as int? : 0;
    msg = jsonMap.containsKey(ConstantUtil.msg) ? jsonMap[ConstantUtil.msg] as String? : "";
    // 存在data
    if (jsonMap.containsKey(ConstantUtil.data)) {
      data = jsonMap[ConstantUtil.data] as T;
    }

    /// response自定以追加的一些字段处理
    tag = jsonMap.containsKey(ConstantUtil.tag) ? jsonMap[ConstantUtil.tag] : 9;
    method = jsonMap.containsKey(ConstantUtil.method) ? jsonMap[ConstantUtil.method] : "";
    baseUrl = jsonMap.containsKey(ConstantUtil.baseUrl) ? jsonMap[ConstantUtil.baseUrl] : "";
    path = jsonMap.containsKey(ConstantUtil.path) ? jsonMap[ConstantUtil.path] : "";
    queryParameters = jsonMap.containsKey(ConstantUtil.queryParameters) ? jsonMap[ConstantUtil.queryParameters] : null;
    desc = jsonMap.containsKey(ConstantUtil.desc) ? jsonMap[ConstantUtil.desc] : "";
  }

  /// 手动重写toString 方法,方便查看日志
  
  String toString() {
    var _code = "code:$code\n";
    var _msg = "msg:$msg\n";
    var _data = json.encode(data).toString();
    var _dataString = "data:$_data\n";
    var _tag = "tag:$tag\n";
    var _method = "method:$method\n";
    var _baseUrl = "baseUrl:$baseUrl\n";
    var _path = "path:$path\n";
    var _desc = "path:$desc\n";
    var _queryParameters = jsonEncode(queryParameters);
    var _queryParametersString = "queryParameters:$_queryParameters\n";

    return _code + _msg + _dataString + _tag + _method + _baseUrl + _path + _desc + _queryParametersString;
  }

  /// 提供自带的打印函数
  void toLog() {
    LoggerUtil().d(toString());
  }
}

catch处理

  /// 对 DioException进行解析,基本覆盖大部分错误类型了
  ResponseEntity _onDioException(DioException err) {
    var errType = err.type;
    var path = err.requestOptions.path;
    var data = err.requestOptions.data;
    var queryParameters = err.requestOptions.queryParameters;
    var baseUrl = err.requestOptions.baseUrl;
    var method = err.requestOptions.method;

    ResponseEntity baseResponseEntity = ResponseEntity(0, "", data, 9, method, baseUrl, path, "", queryParameters);

    ///连接超时
    if (errType == DioExceptionType.connectionTimeout) {
      baseResponseEntity.msg = "连接超时";
      baseResponseEntity.desc = "连接超时";
    }

    ///发送超时
    if (errType == DioExceptionType.sendTimeout) {
      baseResponseEntity.msg = "发送超时";
      baseResponseEntity.desc = "发送超时";
    }

    ///接收超时
    if (errType == DioExceptionType.receiveTimeout) {
      baseResponseEntity.msg = "接收超时";
      baseResponseEntity.desc = "接收超时";
    }

    ///证书损坏
    if (errType == DioExceptionType.badCertificate) {
      baseResponseEntity.msg = "证书损坏";
      baseResponseEntity.desc = "证书损坏";
    }

    ///返回内容问题
    if (errType == DioExceptionType.badResponse) {
      baseResponseEntity.msg = "返回内容问题";
      baseResponseEntity.desc = "返回内容问题";
    }

    ///请求取消
    if (errType == DioExceptionType.cancel) {
      baseResponseEntity.msg = "请求取消";
      baseResponseEntity.desc = "请求取消";
    }

    ///连接错误-无网络
    if (errType == DioExceptionType.connectionError) {
      baseResponseEntity.msg = "连接错误-无网络";
      baseResponseEntity.desc = "连接错误-无网络";
    }

    ///未知错误
    if (errType == DioExceptionType.unknown) {
      baseResponseEntity.msg = "未知错误";
      baseResponseEntity.desc = "未知错误";
    }
    return baseResponseEntity;
  }

针对ResponseEntity中, T? data 的处理, 稍后补上, 先走通请求…

— 数据转模型看这个
[Flutter3] Json转dart模型举例

对于泛型T的处理, 直接把 json转model的model类型传入泛型就可获取数据

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到