Flutter(二十一)——dio库

简介: Flutter(二十一)——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();
  @override
  Future<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();
相关文章
|
6月前
|
存储 JavaScript 前端开发
盘点主流 Flutter 状态管理库2024
状态管理是每个应用不可缺少的,本文将会盘点下主流的状态管理包。
339 2
盘点主流 Flutter 状态管理库2024
|
10天前
|
存储 缓存 Dart
Flutter&鸿蒙next 封装 Dio 网络请求详解:登录身份验证与免登录缓存
本文详细介绍了如何在 Flutter 中使用 Dio 封装网络请求,实现用户登录身份验证及免登录缓存功能。首先在 `pubspec.yaml` 中添加 Dio 和 `shared_preferences` 依赖,然后创建 `NetworkService` 类封装 Dio 的功能,包括请求拦截、响应拦截、Token 存储和登录请求。最后,通过一个登录界面示例展示了如何在实际应用中使用 `NetworkService` 进行身份验证。希望本文能帮助你在 Flutter 中更好地处理网络请求和用户认证。
127 1
|
4月前
|
JSON Dart API
Flutter dio http 封装指南说明
本文介绍了如何实现一个通用、可重构的 Dio 基础类,包括单例访问、日志记录、常见操作封装以及请求、输出、报错拦截等功能。
106 2
Flutter dio http 封装指南说明
|
4月前
|
敏捷开发 前端开发 程序员
Hugeicons Flutter 图标库 | 4000+ 开源免费
在全栈开发的征途中,设计素材的匮乏往往是程序员的一大挑战,尤其是那些为MVP产品增添魅力的元素,比如图标(icons)。 一个优秀的免费图标库,对于快速搭建原型、优化视觉效果至关重要。今天,让我们聚焦于Flutter开发者的一个福音——Hugeicons图标库,它蕴藏着超过4000枚精心设计的图标,为你的应用程序注入无限创意潜力。
114 0
Hugeicons Flutter 图标库 | 4000+ 开源免费
|
3月前
|
存储 缓存 安全
Flutter Dio进阶:使用Flutter Dio拦截器实现高效的API请求管理和身份验证刷新
Flutter Dio进阶:使用Flutter Dio拦截器实现高效的API请求管理和身份验证刷新
302 0
|
3月前
|
Dart API
状态管理的艺术:探索Flutter的Provider库
状态管理的艺术:探索Flutter的Provider库
46 0
|
6月前
|
开发框架 API 开发者
Flutter的动画:实现方式与动画库的技术探索
【4月更文挑战第26天】探索Flutter动画机制与库:基础动画、自定义动画、物理动画及Lottie、AnimatedWidgets、EasyAnimations等库的应用,助开发者实现丰富动画效果,提升用户体验。同时,了解性能优化技巧,如避免重绘、利用离屏渲染和GPU加速,确保动画流畅。 Flutter为移动应用开发带来强大动画支持。
|
6月前
|
安全 网络安全 开发工具
对象存储oss使用问题之flutter使用http库进行post请求文件上传返回400如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
254 1
|
6月前
|
存储 容器
Flutter 应用服务:主题、暗黑、国际化、本地化-app_service库
Flutter 应用服务:主题、暗黑、国际化、本地化-app_service库
274 0
|
6月前
|
Linux 开发者 iOS开发
Flutter笔记:桌面应用 窗口定制库 bitsdojo_window
Flutter笔记:桌面应用 窗口定制库 bitsdojo_window
347 0