Flutter dio 3.2.2 简单封装思路(网络层)

1. Http dio 库(3.2.2)

Flutter 里面提供了网络请求的api ,不过直接使用起来会有点麻烦,于是有了很多第三方的网络库,dio 就是其中之一,也是相对比较成熟的库。那为什么选 dio 呢?

官方描述: dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等

而且使用简单,不过我们在使用时候,还是需要简单封装,便于以后切换库。也让代码更加清晰易用。

封装的简单目录结构:

一个HttpHelper 工具类,CommonInterceptor 拦截器,HttpIOException 异常封装


目录

2. 单例

通过dart 自带的 factory 工厂模式,进行单例设计。
调用是时,直接 HttpUtil httpUtil = HttpUtil() 即可。

_httpInstance 以及 _init都是对外不可见。(dart 里面 _ 开头为内部方法、内部变量)

class HttpUtil {
  factory HttpUtil() => _httpInstance();
  static HttpUtil _instance;
  
  static HttpUtil _httpInstance() {
    if (_instance == null) {
      _instance = HttpUtil._init();
    }
    return _instance;
  }
}

3. 基础网络属性设置

dio 中基础的网络设置,在BaseOptions 中进行设置.

这里简单设置了 contentType,连接超时时间,接收超时时间,以及host ( baseUrl 的设置 )。相对固定的一些基础参数可以直接在新建的时候设置,一些动态的数据,可以通过拦截器的形式动态添加或设置

设置好的参数给 new Dio 进行dio 创建。

  HttpUtil._init() {
    orgOption = BaseOptions(
        contentType: CONTENT_TYPE,
        connectTimeout: CONNECT_TIMEOUT,
        receiveTimeout: RECEIVE_TIMEOUT,
        baseUrl: HOST);
    _dio = new Dio(orgOption);
  }

BaseOptions的其他参数:


接收参数

4. 拦截器设置

使用过拦截器方知拦截器的重要性,拦截器多网络上的处理至关重要,可以接解决很多疑难需求。

拦截器是顺序调用,最先添加的先调用,后添加的后调用

dio 也提供了拦截器的设置。这里简单做一个封装:

  //拦截器添加
  addInterceptor(Interceptor interceptor) {
    if (null != _dio) {
      _dio.interceptors.add(interceptor);
    }
  }

  addInterceptors(List<Interceptor> interceptorList) {
    if (null != _dio) {
      _dio.interceptors.addAll(interceptorList);
    }
  }

新建拦截器

拦截器有三个方法可以实现拦截:、
1 . FutureOr<dynamic> onRequest(RequestOptions options) => options;
请求出去之前的处理

2 . FutureOr<dynamic> onResponse(Response response) => response;
请求结果回来的处理

3 . FutureOr<dynamic> onError(DioError err) => err;
请求发生异常时候的处理

这里新建两个拦截器:

  1. 通用的请求头
  2. 网络错误处理,做统一信息出来

CommonInterceptor.dart:

///可以按需要添加拦截器,实现一些通用的功能,例如统一的请求头,统一的参数添加
///下面是例子

class CommonHeaderInterceptor extends Interceptor {
  @override
  FutureOr<dynamic> onRequest(RequestOptions options) {
    options.headers.addAll({
      "deviceId":"123444",
      "requestId":"ddfsgg"
    });
    return super.onRequest(options);
  }
}

class ErrorInterceptor extends Interceptor {
  @override
  FutureOr<dynamic> onError(DioError err) {
    print(err.type);//也可以区分类型,自定义message;
    if(null != err.response) {
      err.message = "网络错误请稍后重试(" + err.response.statusCode.toString() + ")";
    } else if(null != err.request) {
      err.message = "网络异常,请检查网络情况";
    }
    return super.onError(err);
  }
}

5. 异常封装

dio 本来就封装了 DioError ,不过相对来说,DioError比较复杂,也不一定适合所有的需求,故此,做一个简单的封装。在接收到 DioError 或者其他异常的时候,通过 Future.error 抛出,自定义的异常,定义抛出信息。

class HttpIOException implements Exception{

  int code;
  String message;
  HttpIOException(this.code,this.message);
}

6. 调用

对外的调用比价简单,提供 get post 等api 外部调用, 返回 Future<dynamic> ,进行函数式调用返回。

如何调用:

    httpUtil.post("getServerTimestamp", getRequestData())
        .then((resp) {
          //这里可以做想要的转换,也可以什么都不做
           HomePageResp result = new HomePageResp.fromJson(resp);
           return result;
        });

最后直接来个完整的代码

import 'package:dio/dio.dart';
import 'dart:io';
import 'dart:async';
import 'package:move_forever_app/core/http/HttpIOExcepiton.dart';
import 'dart:convert';


const String GET = "get";
const String POST = "post";

const String HOST = "https://your_host_url.com/";
const int CONNECT_TIMEOUT = 10000;
const int RECEIVE_TIMEOUT = 3000;
final ContentType CONTENT_TYPE = ContentType.json;

typedef ErrorCallback = void Function(int count, String msg);


class HttpUtil {
  factory HttpUtil() => _httpInstance();
  static HttpUtil _instance;
  Dio _dio;
  BaseOptions orgOption;

  static HttpUtil _httpInstance() {
    if (_instance == null) {
      _instance = HttpUtil._init();
    }
    return _instance;
  }

  HttpUtil._init() {
    orgOption = BaseOptions(
        contentType: CONTENT_TYPE,
        connectTimeout: CONNECT_TIMEOUT,
        receiveTimeout: RECEIVE_TIMEOUT,
        baseUrl: HOST);
    _dio = new Dio(orgOption);
  }

  //拦截器添加
  addInterceptor(Interceptor interceptor) {
    if (null != _dio) {
      _dio.interceptors.add(interceptor);
    }
  }

  addInterceptors(List<Interceptor> interceptorList) {
    if (null != _dio) {
      _dio.interceptors.addAll(interceptorList);
    }
  }

  //post
  Future<dynamic> post (String path,postData) {
    return request(path, POST, postData);
  }

  //get
  Future<dynamic> get (String path) {
    return request(path, GET, null);
  }

  Future<dynamic> request(String path, String mode, postData) async {
    try {
      switch (mode) {
        case GET:
          var getResponse = await _dio.get(path);
          return new Future<dynamic>((){
            return getResponse.data;
          });
        case POST:
          //做一层json 转换
          var postResponse = await _dio.post<Map<String,dynamic>>(path, data: json.encode(postData));
          return new Future<dynamic>((){
            return postResponse.data;
          });
      }
    } on DioError catch (exception) {
      return new Future.error(new HttpIOException(exception.response.statusCode, exception.message));
    } catch (error) {
      return new Future.error(new HttpIOException(-2, error.toString()));
    }
    return new Future.error(new HttpIOException(-1, "not supported"));
  }
}

7. 总结

封装比较简单,这个也是dio本来就是一个比较完善的库的原因。

但是里面还有很多可以扩展的地方,拦截器可以按需要添加,异常封装也可以按需进行,get post 只是最基本的请求方式,还可以对其他进行添加封装。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容