实现后的效果

      case 5:{try{var res = await DioManager().friend_getSelectionTopic(params: {});print('成功msg-----------'+res.msg);print('成功code-----------'+res.code);print('成功code-----------'+res.data.toString());}catch(err){print('最外部捕获msg-----------'+err.msg);print('最外部捕获code-----------'+err.code);print('最外部捕获data-----------'+err.data.toString());}}break;logo如下::::::
I/flutter (29319): [START----发起get请求---->:https://t-ebankhome.reganfund.com/appapi/apib/v3/friends/getSelectionTopic
I/flutter (29319): [GET----请求参数--->:null
I/flutter (29319): ======= json反序列化后的dynamic对象 ======== :  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiMzQiLCIxIl0sImV4cCI6MTU5ODQzMjY3MSwiaWF0IjoxNTk3ODI3ODcxfQ.lLr7xG443XBU0AES2P2CFAEB3Rixm11_7d8U6Om33ek
I/flutter (29319):  read  is  ok ,,,,,
I/flutter (29319): [END_SUCCESS_CODE_OK=====获取GET返回结果=====>:{"code":"000","msg":"成功","datas":{"total":2,"data":[{"friendsClassifyId":41,"fileUrl":"https://t-ebankhome.reganfund.com/appapi/upload/data/ad/20200615131741297.png","classifyName":"基金"},{"friendsClassifyId":40,"fileUrl":"https://t-ebankhome.reganfund.com/appapi/upload/data/ad/20200615131821557.png","classifyName":"保险"}]}}
I/flutter (29319): 成功msg-----------成功
I/flutter (29319): 成功code-----------000
I/flutter (29319): 成功code-----------{total: 2, data: [{friendsClassifyId: 41, fileUrl: https://t-ebankhome.reganfund.com/appapi/upload/data/ad/20200615131741297.png, classifyName: 基金}, {friendsClassifyId: 40, fileUrl: https://t-ebankhome.reganfund.com/appapi/upload/data/ad/20200615131821557.png, classifyName: 保险}]}乱改一下URL, 看看失败效果
I/flutter (29319): [START----发起get请求---->:https://t-ebankhome.reganfund.com/appapi/apib/v3/friends/getSelectionTopicss
I/flutter (29319): [GET----请求参数--->:null
I/flutter (29319): ======= json反序列化后的dynamic对象 ======== :  eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiMzQiLCIxIl0sImV4cCI6MTU5ODQzMjY3MSwiaWF0IjoxNTk3ODI3ODcxfQ.lLr7xG443XBU0AES2P2CFAEB3Rixm11_7d8U6Om33ek
I/flutter (29319):  read  is  ok ,,,,,
I/flutter (29319): [END_ERROR=====GET-Error =====>:Http status error [404]
I/flutter (29319): 最外部捕获msg-----------服务器响应异常(404,503等)Http status error [404]
I/flutter (29319): 最外部捕获code------------903
I/flutter (29319): 最外部捕获data-----------{}

要实现的目的

我们需要一个类, 用来方便快捷的调用Api接口,发送报文,获取返回的数据,同时还可以进行一些公共的操作和钩子函数拦截…
在RN里头, 有axios, 同样的再Flutter里, 我们有Dio ,
但是为了操作和使用方便, 我们需要二次封装一下, 网上代码很多,这边就分享下自己的, 有问题的可以多指正

我这边的需求很简单, 就是需要一个Dio网络管理类. 返回一个类似于Promise的Future 的Response结果, 而且, 这个结果的格式类型,必须是统一的, 这样方便外部使用
所以,这里我人为规定了这样一个类结构

/// 人为规定的Response返回类 - 内部类
class _ResponseData {String msg;String code;Map<String, dynamic> data;_ResponseData({String msg, String, code, Map<String, dynamic> data}) {this.msg = msg;this.code = code;this.data = data;}
}

在使用中, 我基于async/await, 无论是请求成功/失败, 均返回这样一个类对象.方便我外部使用

DioManager 管理类

需要用单例模式创建唯一的类实例. 该实例拥有几个实例对象,从而确保Dio实例的唯一性, 具体实现单例化, 上一篇还是上上一篇, 应该有的

其他的相关代码直接上代码了


import 'package:dio/dio.dart';
import 'package:ebankhome/utils/SharedPreferencesUtils.dart';
import 'dart:io';
import 'dart:math';
import 'dart:async';
import 'package:flutter/foundation.dart';import 'package:ebankhome/utils/GlobalUtils.dart';/// -------------------------------
/// Created with Flutter Dart File.
/// User tianNanYiHao@163.com
/// Date: 2020-08-14
/// Time: 14:58
/// Des: 网络库 Dio 的管理类
/// DioMananger
/// 1.提供Dio的基础配置 √
/// 2.提供 get/post基础功能 √
/// 3.提供 formData 上传文件基础功能 ?
/// 4.提供 下载 的基础功能 ?
/// 5.提供 取消 的基础功能 ?
/// 6.待规划...
///
/// 使用:
/// 无论是请求成功还是失败, 均人为规定返回一个Response对象.{code:string,msg:string,data:dynamic}
/// 在外部调用 await DioManager().xxxrequest(); res/err 均以统一格式返回
///
/// 业务处理:
/// 若请求成功 且 code 成功. 直接抛出Response.data对象
/// 若请求成功 但 code 不匹配(一般性错误code), 直接抛出Response.data对象,交由外部调用方依据code处理对应的catch逻辑
///
/// 特殊处理:
/// 若遇到请求成功,但是业务code不通过(特殊错误码),将不会抛出改Response,不再处理该Response, 且同时处理改错误码对应的逻辑
///
/// 官方文档 Dio: https://github.com/flutterchina/dio/blob/master/README-ZH.md
/// -------------------------------
//////
/// *********************************** 内部私有类 ***********************************
///
/// URL类 - 内部类
class _EbankHomeURL {/// *********************************** V1 ***********************************/// 登录static const String login = '/apib/v1/account/login';/// *********************************** V2 ***********************************/// *********************************** V3 ***********************************/// 查询精选主题static const String friend_getSelectionTopic = '/apib/v3/friends/getSelectionTopic';
}/// 人为规定的Response返回类 - 内部类
class _ResponseData {String msg;String code;Map<String, dynamic> data;_ResponseData({String msg, String, code, Map<String, dynamic> data}) {this.msg = msg;this.code = code;this.data = data;}
}class DioManager {/// *********************************** 实例变量 ***********************************Dio dio; // Dio 的实例对象String dioManageID; // 网络管理类实例的随机id,不必关心final BaseOptions options = BaseOptions(baseUrl: GlobalUtils.GETBASEURL(),connectTimeout: 5000,// 连接URL的超时时间receiveTimeout: 5000,// 接受数据的超时时间headers: {"Content-Type": "application/json;charset=UTF-8",},responseType: ResponseType.json,); // Dio 基础配置/// [DioManager]持有的 - 静态的final实例对象, 并进行初始化static final DioManager _dioManager = DioManager._instance();/// *********************************** 构造函数 ***********************************/// [DioManager]私有的 自定义命名式构造方法, Ps:instance不是关键字, 可随意命名/// 加 _ 表示该命名式构造函数为[DioManager]私有, 外部是不可调用的,/// 从而确保该命名式构造函数的使用, 仅可用来创建 _dioManager 这个静态的final实例对象DioManager._instance() {// 创建Dio的实例对象dio = Dio(options);// 添加拦截器, 可以在其中进行一些公共的处理dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions resOptions) async {// 请求前的拦截resOptions = await _beforRequest(resOptions);return resOptions; // continue},onResponse: (Response response) async {// 返回前的拦截await _beforResponse(response);return response; // continue},// 注: 此处不进行onError的拦截器添加,显然此处出现Error, 将直接向上抛出, 不会走到基础的_get /_post的catch中,// 我们需要_get/_post 中进行catch, 以便于我们使用人为规定的 _ResponseData 类对象//onError:
//      onError: (DioError error) async{//        return error;
//      }));// 验证一下是否是当前dioManageID = "看看ID是啥" + Random().nextInt(1000).toString();}/// 工厂化的主构造函数 - 返回私有的实例对象/// 返回的就是唯一的实例 _dioManagerfactory DioManager() {return _dioManager;}/// *********************************** DioMananger 私有方法 ***********************************/// 请求发送前 - 拦截处理/// 目前提供一个Futrue的异步函数, 用于拦截器中处理异步操作,Future<RequestOptions> _beforRequest(RequestOptions resOptions) async {String requestParams = resOptions.data.toString();String requestMethod = resOptions.method.toString();debugPrint('[' + requestMethod + '----' + '请求参数--->:' + requestParams);// 请求前, 获取一下token塞进报文headersvar token = await SharePreferencesUtils.token(SharePreferencesUtilsWorkType.get);resOptions.headers['token'] = token ?? '';return Future.value(resOptions);}/// 消息返回前 - 拦截处理/// 目前提供一个Futrue的异步函数, 用于拦截器中处理异步操作,Future<Response> _beforResponse(Response response) async {//    debugPrint('[Response----原始数据----> :' + response.toString());// 如果是登录api, 异步转同步执行一下token本地固化,if (response.request.path == _EbankHomeURL.login) {String token = response.data['token'] ?? '';bool saveScuess = await SharePreferencesUtils.token(SharePreferencesUtilsWorkType.save, value: token);saveScuess ? debugPrint('token 保存成功') : debugPrint('token 保存失败');}return Future.value(response);}/// get 请求Future<dynamic> _forget(String url, {Map<String, dynamic> params, bool showLoading = false}) async {final com = Completer();final future = com.future;debugPrint("[START----发起get请求---->:" + dio.options.baseUrl + url);try {Response res = await dio.get(url, queryParameters: params);// 执行业务分发处理_successResponseCheck(com, res);} catch (error) {_errorCheck(com, error);}return future;}/// post 请求Future<dynamic> _forPost(String url, {Map<String, dynamic> params, bool showLoading = false}) async {final com = Completer();final future = com.future;debugPrint("[START----发起post请求---->:" + dio.options.baseUrl + url);try {Response res = await dio.post(url, data: params);// 执行业务分发处理_successResponseCheck(com, res);} catch (error) {_errorCheck(com, error);}return future;}/// 业务层请求结果分发 , 处理特殊的code码/// 抛出 人为规定的 _ResponseData对象_successResponseCheck(Completer com, Response res) {String code = res.data['code'];_ResponseData responseData = _ResponseData();// 业务成功,直接抛出_ResponseData对象if (code == '000' || code == null) {debugPrint('[END_SUCCESS_CODE_OK=====获取' + res.request.method + '返回结果=====>:' + res.toString());// 不同版本Api, 单独处理responseDataresponseData = _getResponseDataWithApiVersion(res);com.complete(responseData);}// 全局错误, 不向外抛出_ResponseData对象. 仅处理退出登录操作, 且请求流程就此终结,else if (code == '021' || code == '022' || code == '023' || code == '024' || code == '025') {debugPrint('[END_SUCCESS_CODE_LOGOUT=====获取' + res.request.method + '返回结果=====>:' + res.toString());// 执行登出操作// 执行登出操作// 执行登出操作// 执行登出操作}// ...其他更多特殊错误码,在此处添加和处理
//    else if(){}// 一般业务性失败错误,直接抛出_ResponseData对象else {debugPrint('[END_SUCCESS_CODE_FAIL=====获取' + res.request.method + '返回结果=====>:' + res.toString());// 不同版本Api, 单独处理responseDataresponseData = _getResponseDataWithApiVersion(res);com.completeError(responseData);}}/// 由于历史原因, 几个不同版本的Api/// 在返回字段上的格式不尽相同, 需要单独处理/// 以确保_ResponseData 数据格式相同_ResponseData _getResponseDataWithApiVersion(Response res) {_ResponseData responseData = _ResponseData();String requestPath = res.request.path;bool isV1 = requestPath.contains('v1', 0);bool isV2 = requestPath.contains('v2', 0);bool isV3 = requestPath.contains('v3', 0);if (isV1) {responseData.msg = res.data['msg'];responseData.code = res.data['code'];res.data.remove('msg'); // 删除内部的多余msg/coderes.data.remove('code');responseData.data = res.data;}if (isV2 || isV3) {responseData.msg = res.data['msg'];responseData.code = res.data['code'];res.data.remove('msg'); // 删除内部的多余msg/coderes.data.remove('code');responseData.data = res.data['datas'];}return responseData;}/// 二次分发异常, 处理特殊的异常/// 抛出 人为规定的 _ResponseData对象_errorCheck(Completer com, DioError error) {debugPrint('[END_ERROR=====' + error.request.method + '-Error =====>:' + error.error.toString());_ResponseData responseData = _ResponseData();DioErrorType errorType = error.type;switch (errorType) {case DioErrorType.DEFAULT:responseData.msg = '请自行排查异常问题===>:' + error.error.toString();responseData.code = '-900';responseData.data = {};return com.completeError(responseData);case DioErrorType.CONNECT_TIMEOUT:responseData.msg = '请求超时' + error.error.toString();responseData.code = '-901';responseData.data = {};return com.completeError(responseData);case DioErrorType.SEND_TIMEOUT:responseData.msg = '响应超时' + error.error.toString();responseData.code = '-902';responseData.data = {};return com.completeError(responseData);case DioErrorType.RESPONSE:responseData.msg = '服务器响应异常(404,503等)' + error.error.toString();responseData.code = '-903';responseData.data = {};return com.completeError(responseData);case DioErrorType.CANCEL:responseData.msg = '请求被取消' + error.error.toString();responseData.code = '-904';responseData.data = {};return com.completeError(responseData);case DioErrorType.DEFAULT:responseData.msg = 'DioManager工作异常,请自行排查问题' + error.error.toString();responseData.code = '-905';responseData.data = {};return com.completeError(responseData);}}/// *********************************** 业务API v1 ***********************************login({Map<String, dynamic> params, bool showLoading = false}) {return this._forPost(_EbankHomeURL.login, params: params, showLoading: showLoading);}/// *********************************** 业务API v2 ***********************************friend_getSelectionTopic({Map<String, dynamic> params, bool showLoading = false}) {return this._forget(_EbankHomeURL.friend_getSelectionTopic, params: params, showLoading: showLoading);}
}

#待补充和后续完善…

Flutter 基于Dio封装网络层相关推荐

  1. flutter基于fijkplayer封装播放器皮肤

    由于flutter-fijkplayer播放器皮肤实在不能符合市场上的需求只能由自己重新根据官方源码来修改成自己需要的皮肤,但过程需要阅读源码和理解里面的api是干嘛的导致起码都得花个一两小时去处理, ...

  2. dio设置自定义post请求_基于dio库封装flutter项目的标准网络框架

    网络框架是每个应用的基石,封装一个好的网络框架不仅是项目的一个好的开始,并且直接影响到随后项目的稳定性和可扩展性.在移动开发的各个端都有非常赞的网络请求基础框架,比如Android的okhttp库.s ...

  3. Flutter中基于Dio实现Token Refresh

    Flutter中基于Dio实现Token Refresh 1. 背景介绍 目前项目在采用Flutter开发一款App,该工程中采用Dio框架作为网络请求框架,用户登录方面采用 OAuth2 协议.众所 ...

  4. flutter 基于掘金App实现的UI页面

    flutter 基于掘金App实现的UI页面 项目地址: https://github.com/JunIce/juejin_flutter_ui 项目启动 众所周知的原因, 国内能查到的有关flutt ...

  5. dio设置自定义post请求_使用Dio封装ajax的post和get操作

    dio是经常使用到的一个包,为flutter的日常开发提供了很多支持.本文主要描述如何使用Dio封装ajax请求. dio的依赖:dependencies: dio: 3.0.8 dio包的导入:im ...

  6. php面向对象分页,PHP基于面向对象封装的分页类示例

    本文实例讲述了php基于面向对象封装的分页类.分享给大家供大家参考,具体如下: class page { protected $num;//每页显示条数 protected $total;//总记录数 ...

  7. vue前端上传文件夹的插件_基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件...

    1. 前言 之前公司要在管理系统中做一个全局上传插件,即切换各个页面的时候,上传界面还在并且上传不会受到影响,这在vue这种spa框架面前并不是什么难题.然而后端大佬说我们要实现分片上传.秒传以及断点 ...

  8. 基于jquery的php分页,基于jQuery封装的分页组件

    前言: 由于项目需要实现分页效果,上jQuery插件库找了下,但是木有找到自己想要的效果,于是自己封装了个分页组件. 思路: 主要是初始化时基于原型建立的分页模板然后绑定动态事件并实现刷新DOM的分页 ...

  9. EasyRTSPClient:基于live555封装的支持重连的RTSP客户端RTSPClient

    今天先简单介绍一下EasyRTSPClient,后面的文章我们再仔细介绍EasyRTSPClient内部的设计过程: EasyRTSPClient:https://github.com/EasyDar ...

最新文章

  1. “service httpd does not support chkconfig” 問題
  2. 机器学习实践:onnx模型转为Tensorflow2的pb模型2020
  3. 关于c/c++/obj-c的混合使用 (2010-06-22 10:05:33)
  4. $router VS $route
  5. Hyper-V Server 存储空间
  6. Leetcode: Increasing Triplet Subsequence
  7. 第55章、播放视频(从零开始学Android)
  8. 怎么看xp计算机是32位还是64位,教你查看XP系统的不同32位还是64位详细的步骤
  9. tableau度量值计算_度量值与度量名称
  10. Kubernetes 的网络原理 (五)---CNI网络模型
  11. No such file or directory @ rb_sysopen
  12. three.js 控制动画进度 进度条拖拽控制
  13. 交换机最多可以接几个_【技术】详解一个交换机能带动多少个网络监控摄像头?...
  14. 【Python】html格式转md格式
  15. video视频播放过程抓取图片/截图并在浏览器端下载
  16. python tricks_Python Tricks
  17. 解决鼠标右键菜单在光标左边问题
  18. GreenPlum 外部表external table 实战
  19. 云通信巨头Twilio市值超600亿美元,声网与容联云与其差距在哪?
  20. php调用拼多多api模板,PHP调用拼多多API模板

热门文章

  1. 副业收入是我做程序员的2倍!副业这么有 “钱”景,我要考虑转行吗?
  2. 最全随机抽样算法(从N个数中抽取M个等)集合
  3. 银河麒麟+FT2000环境下在线安装QT
  4. 安卓APP之加固技术
  5. DM7数据守护集群部署
  6. matlab抗饱和 符号,MATLAB作图特殊符号大全
  7. charles安装及设置(三星手机)
  8. masquerade词根词缀_GRE填空题-同向逻辑和词汇记忆法
  9. 爬虫学习2-相关原理
  10. 如何压缩PDF文件?这3个PDF在线压缩工具免费又好用!