本文目录

  • 前言
  • 基本用法
  • dio单例
  • dio拦截器
  • 拦截器链
  • dio适配器

前言

前面介绍了dart语言自带的网络请求库httpClient,以及官方推荐的网络请求库http,但我们的网络请求其实千变万化,并不仅仅只是请求一个网页获取某种数据这一种需求。

有时候,我们也需要在网络请求之前以及之后做些准备工作,这就涉及到如果监听我们的网络请求过程,这个时候前面的网络请求方式显然不能满足我们的需求,所以我们需要借助强大的第三方网路请求库dio。

dio库是Flutter中文网提供的一个强大的http请求库,在Github上它的star数量已经超过3000次,如果你用Java开发过Android程序,肯定用到过OkHttp库,其实它们两有些相似。它支持文件的上传/下载,Cookie管理,FormData,请求/取消,拦截器等操作。下面博主将详细介绍dio库的用法。

基本用法

通过在网络请求中,基本用法如前面一样就是get与post请求。比如通过get请求获取一个网址的内容,可以通过如下代码实现:

_getData() async{try{Response response=await Dio().get("https://www.baidu.com/");print(response);}catch(e){print(e);}

代码很简单这里就不做过多的赘述,接着我们再来看看post请求,代码如下:

_postData() async{try{Response response=await Dio().post("https://www.baidu.com/",data: {});print(response);}catch(e){print(e);}}

与get请求唯一的区别是多了一个参数传递,通过键值对的方式。

dio单例

一个dio实例可以发起多个网络请求。很多时候,在App里只存在一个http数据源,且有一些公共的配置项,比如公共的头文件,公共的请求地址,超时设置等。在这些情况下,我们可以考虑使用dio库提供的单例模式,这也是dio库推荐的用法,便于程序员管理,创建的代码如下:

    var dio=new Dio(new BaseOptions(baseUrl: "http://liyuanjinglyj.com/demo",//链接connectTimeout: 5000,//链接超时receiveTimeout: 100000,//响应超时headers: {//请求头HttpHeaders.userAgentHeader:"dio","api": "1.0.0",},contentType: ContentType.json,//请求Json数据responseType: ResponseType.plain//响应数据为文本));

从上面的实例中我们可以看到,在初始化dio实例时,我们传入了一个BaseOptions的配置项,里面可以设定一些基本且共用的信息,上面注释这些就是,这样更便于我们对App网络的请求进行统一的管理。

dio拦截器

开头博主已经说过了一种需求就是监听网络请求,在之前以及之后处理一些实际的需求,这里我们就需要用到dio库的拦截器,使用代码如下:

dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options){//请求之前处理一些事情return options;},onResponse: (Response response){//请求返回数据之后处理一些事情return response;},onError: (DioError error){//当请求失败时,处理事情return error;}));

上面通过单例模式创建了一个dio变量,这里直接使用起来。可以看到,在拦截器Request处理时,我们可以直接返回options,这个时候会继续处理then方法里的逻辑,如果你想完成请求并返回一些自定义的数据,可以返回一个response对象或返回dio.resolve(data),这样请求将会被终止,上层的then会被调用,then中返回的数据将是你自定义的数据data。

如果你想终止请求并触发一个错误,你可以返回一个DioError对象,或返回dio.reject(errMsg),这样请求将会被终止并触发异常。比如,也可以这样写:

dio.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions options){//请求之前处理一些事情return dio.resolve("error");},
));
Response response= await dio.get("网址");

涉及到拦截器,实际业务中我们可以还有一种需求,比如我们可能需要锁定/解锁拦截器,一旦请求/响应的拦截器被锁定,接下来的请求/响应,将会在进入拦截器之前进行排队等待,直到解锁成功,这里排队的请求/响应才会继续执行,所以在一些串行化请求/响应的场景中,我们也需要用到拦截器,我们可以使用lock/unlock(也也就是操作系统中的锁)来实现,代码如下:

var crsfToken=null;var dio=new Dio();var tokenDio=new Dio();dio.interceptors.add(InterceptorsWrapper(onRequest: (Options options){print("发送请求之前");if(crsfToken==null){dio.lock();return tokenDio.get("网址").then((d){options.headers["csrfToken"]=crsfToken=d.data['data']['token'];return options;}).whenComplete(()=>dio.unlock());}else{options.headers["csrtToken"]=crsfToken;return options;}},));

在上述代码中,我们创建了一个实例用于请求token,在发送请求时,我们会被请求的拦截器拦截。如果我们首次访问接口,在没有携带token的情况下,代码就会创建另一个dio实例并通过异步任务去获取token,获取完成之后,dio会把它设置到headers里面,并把token作为请求参数发送,然后调用unlock方法进行解锁。

比如我们请求需要登录后才能操作的网络请求时,我们需要先获取cookie,这里就可以使用上面类似的代码,而且你也可以在调用拦截器的clear()方法来清空等待队列。

拦截器链

其实拦截器不止一个。在Android的OkHttp框架里,就有拦截器链的概念,在dio库中也一样,你可以通过编译器查看其源码,其实拦截器都是放在ListMixin里面的,最终需要执行_executeInterceptors来处理每一个拦截器,代码如下:

Future _executeInterceptors<T>(T ob,f(Interceptor inter,T ob)) async{for(var inter in interceptors){var res=await _assureFutrue(f(inter,ob));if(res!=null){if(res is T){ob=res;continue;}if(res is Response || res is DioError) return res;return res;}}return ob;
}

通过上面代码,就比较容易理解它的工作原理了。我们可以根据需求在代码中添加多个拦截器,比如,我们可以添加日志拦截器,代码如下:

dio.interceptors.add(LogInterceptor(responseBody: false));

在比如,如果我们需要添加Cookie进行管理,也能放在拦截器里面,可以这样写,代码如下:

dio.interceptors.add(CookieManager(CookieJar()));

dio适配器

dio库还能抽象出适配器来方便切换和定制顶层的网络库。比如,在Flutter中我们可以通过自定义HttpClientAdapter将http请求转发到Native中,然后再由Native统一发送请求。再比如,将来某一天OkHttp也提供了Dart版本,这个时候可以通过适配器无缝切换到OkHttp库,而不用修改之前的代码。

dio使用DefaultHttpClientAdapter作为其默认的HttpClientAdapter,DefaultHttpClientAdapter使用dart:io:HttpClient来发起网络请求,代码如下:

class LYJAdapter extends HttpClientAdapter{static const String host="liyuanjinglyj.com";static const String base="http://$host";DefaultHttpClientAdapter _adapter=DefaultHttpClientAdapter();@overrideFuture<ResponseBody> fetch(RequestOptions options, Stream<List<int>> requestStream, Future cancelFuture) async{Uri uri=options.uri;if(uri.host==host){switch(uri.path){case "/demo":return ResponseBody.fromString(jsonEncode({"errCode":0,"data":{"path":uri.path}}),200,headers: DioHttpHeaders.fromMap({HttpHeaders.contentTypeHeader:ContentType.json,}),);case "/download":return ResponseBody(File("./README.MD").openRead(),200,headers: DioHttpHeaders.fromMap({HttpHeaders.contentLengthHeader:File("./README.MD").lengthSync(),}),);default:return ResponseBody.fromString("",404,headers: DioHttpHeaders(),);}}return _adapter.fetch(options,requestStream,cancelFuture);}
}

这里我们定义了一个LYJAdapter,并且设置了base作为baseUrl,这个一般根据服务器更改。当“uri.host==host”时,则进入switch条件分支判断逻辑。比如"/demo",就是请求的"http://liyuanjinglyj.com/demo"。最后通过_adapter.fetch来执行返回Future。

当然这里我们还需要设置适配器,设置适配器的代码如下:

var dio=new Dio();
dio.httpClientAdapter=LYJAdapter();

Flutter(二十一)——dio库相关推荐

  1. Flutter网络请求Dio库的使用及封装

    Dart语言内置的HttpClient实现了基本的网络请求相关的操作.但HttpClient本身功能较弱,很多网络请求常用功能都不支持,因此在实际项目中,我们更多是使用dio库实现网络请求. 注:Fl ...

  2. Flutter开发之HTTP网络请求:dio库(28)

    dio是Flutter中文网开源的一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消.Cookie管理.文件上传/下载.超时等- 第三方库 dio实现g ...

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

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

  4. 西安交大计算机考研软件工程编程题库(二十一)

    西安交大计算机考研软件工程编程题库(二十一) 鄙人今年备考,主要目的在于记录学习历程,望道友们勿喷~ 希望能做到每日一题~ 开始炼丹~ 上篇链接:西安交大计算机考研软件工程编程题库(二十) 下篇链接: ...

  5. 线程本地存储器——Windows核心编程学习手札之二十一

    线程本地存储器 --Windows核心编程学习手札之二十一 C/C++运行期库使用线程本地存储器,运行期库是在多线程应用程序出现前设计的,因此运行期库里的大多数函数是用于单线程应用程序的.函数strt ...

  6. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  7. 二十二、statsmodels库的使用

    @Author:By Runsen @Date: 2019/07/26 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘课严 ...

  8. 数据科学和人工智能技术笔记 二十一、统计学

    二十一.统计学 作者:Chris Albon 译者:飞龙 协议:CC BY-NC-SA 4.0 贝塞尔校正 贝塞尔的校正是我们在样本方差和样本标准差的计算中使用 n−1n-1n−1 而不是 nnn 的 ...

  9. Citrix 服务器虚拟化之二十一 桌面虚拟化之部署Provisioning Services

    Citrix 服务器虚拟化之二十一  桌面虚拟化之部署Provisioning Services Provisioning Services 是Citrix 出品的一系列虚拟化产品中最核心的一个组件, ...

最新文章

  1. python3的数据类型以及模块的含义
  2. spring boot2.x使用rabbitmq
  3. (5.17更新)2011.5.21项管考试论文关注点
  4. 嵌入式Linux学习2——Linux常用指令2
  5. 安装opencms时遇到问题及解决方法
  6. 【科普】让人头秃的理论:什么是“奥卡姆剃刀”原理?
  7. JS - 讨论 - 编码习惯 - JavaScript代码到底要不要写分号?
  8. 设计模式----Adapter(适配器)
  9. 【java】java JUC 同步器框架 AQS AbstractQueuedSynchronizer源码图文分析
  10. 采用Locust对grpc协议进行压测
  11. 2020-01-14 IP/TCP/UDP 对应的RFC编号
  12. python基本代码教程-python基础教程第三版源代码
  13. 实战MEF(4):搜索范围
  14. Twitter数据抓取的方法(三)
  15. 如何覆盖上一次commit_如何在 Linux 上一次性批量重命名一组文件?
  16. js 实现简繁体互相转换(字符串)
  17. NDoc 用户指南(一)
  18. 台式计算机配置作业,大学计算机上机课作业.doc
  19. java实现简易五子棋
  20. java正则提取字符串中的符号汉字数字字母

热门文章

  1. 彩票摇奖 java_Java课程设计——彩票购买抽奖系统
  2. 组织机构代码生成规则
  3. MOS 管的区分N管和P管和检测
  4. 大家都说工作越干越有经验,为啥会有35岁程序员失业危机?
  5. 【最新消息】交大复旦同济华师大应届毕业生可直接落户上海
  6. 【ERNIE Bot】百度 | 文心一言初体验
  7. 一种RK3399+MIPI+FPGA的高速工业相机的设计方案(一)
  8. 【笔记】雾计算中移动应用的优先级约束任务调度
  9. jzxx1877烤面包
  10. 微信企业邮箱的POP3、SMTP、IMAP地址是什么?