时间: 2020-08-31|tag:57次围观|0 条评论

1. Http dio 库(3.2.2)

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

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

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

封装的简单目录结构:

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

Flutter dio 3.2.2  简单封装思路(网络层)插图
目录

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的其他参数:

Flutter dio 3.2.2  简单封装思路(网络层)插图1
接收参数

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 只是最基本的请求方式,还可以对其他进行添加封装。

文章转载于:https://www.jianshu.com/p/892b1c17b32b

原著是一个有趣的人,若有侵权,请通知删除

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自起风了,原文地址《Flutter dio 3.2.2 简单封装思路(网络层)
   

还没有人抢沙发呢~