Flutter 基于网络请求框架Dio的二次封装


Flutter  基于网络请求框架Dio的二次封装


前言

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

使用

  • 使用dio get请求一条json数据
<code>getRequest() async {    Response response = await Dio()        .get('https://...');    this.setState(() {      result= response.toString();    });  }/<code>
  • 利用dio post请求注册一个新用户
<code>postRequest() async {    var path = "https://.../user/register";    var params = {      "username": "yth",      "password": "123456",      "repassword": "123456"    };    Response response =        await Dio().post(path, queryParameters: params);    this.setState(() {      result= response.toString();    });  }/<code>

二次封装

在项目开发过程中随着项目越写越大,代码量也会成倍的增加,隔离业务抽取共性代码的思想自然而然的出现在一个严于律己的开发者脑子里,特别是像网络请求这种操作,好的封装不仅会减少冗余代码更能让代码层级变得清晰可读,下面笔者就带着自己的理解对Dio做一个简单封装,笔者自认为才疏学浅,代码中如有写的不好的地方还请各位不吝赐教。


一般我们在处理工具类时都会用到单例的思想,做为一个项目全局的网络请求工具类,我们同样也把DioUtils封装成单例模式

<code>static DioUtils getInstance() {    if (_instance == null) {      _instance = new DioUtils();    }    return _instance;  }/<code>

对于请求参数的初始化跟一些网络配置,Dio为开发者提供了BaseOptions、Options、RequestOptions可选Options配置,三者的优先级关系依次递增

先来看下BaseOptions给我们提供的可供配置的参数:

<code>BaseOptions({  String method,  int connectTimeout,  int receiveTimeout,  Iterable<cookie> cookies,  this.baseUrl,  this.queryParameters,  Map<string> extra,  Map<string> headers,  ResponseType responseType = ResponseType.json,  ContentType contentType,  ValidateStatus validateStatus,  bool receiveDataWhenStatusError = true,  bool followRedirects = true,  int maxRedirects = 5, RequestEncoder requestEncoder,  ResponseDecoder responseDecoder,})/<string>/<string>/<cookie>/<code>

上面构造方法中的属性读者基本都能见名知意做到自解释,我就不单独解释了,贴上一段我在代码里的配置:

<code>//请求参数配置   _baseOptions = new BaseOptions(     baseUrl: BASE_URL,     //请求服务地址     connectTimeout: 5000,     //响应时间     receiveTimeout: 5000,     headers: {       //需要配置请求的header可在此处配置     },     //请求的Content-Type,默认值是[ContentType.json]. 也可以用ContentType.parse("application/x-www-form-urlencoded")     contentType: ContentType.json,     //表示期望以那种格式(方式)接受响应数据。接受三种类型 `json`, `stream`, `plain`, `bytes`. 默认值是 `json`,     responseType: ResponseType.json,   );然后把_baseOptions通过参数的形式传入Dio实例中完成配置的初始化/<code>

然后把_baseOptions通过参数的形式传入Dio实例中完成配置的初始化

<code>//创建dio实例    _dio = new Dio(_baseOptions);/<code>

接下来我把我们开篇用DIO做的简单GET、POST方法用我们新写的工具类封装完成后重新做请求,让我们来一起感受下封装带来的便利。

  • 封装GET请求
<code> /**  * get请求  */  get(url, {data, options, cancleToken}) async {    print('get request path ------${url}-------请求参数${data}');    Response response;    try {      response = await _dio.get(url,          queryParameters: data, options: options, cancelToken: cancleToken);      print('get success ---${response.data}');    } on DioError catch (e) {      print('请求失败---错误类型${e.type}');    }    return response.data;  }/<code>

利用我们封装好的get请求方法,开篇的get请求只需改为:

<code>getRequest() async {    String result= await DioUtils().get('/banner/json');    this.setState(() {      resultJson = result;    });  }/<code>

在刚刚讲BaseOptions时,我们提到还有Options、RequestOptions可供配置,我们提到可以利用Options的优先级重新覆盖掉原先在工具类里设置好的网络配置,比如修改提前在header中设置好的请求内容。 还是上述代码,我先修改_baseOptions中的header的配置如下:

我们利用Options修改BaseUrl后的请求url

<code>_baseOptions = new BaseOptions(     baseUrl: BASE_URL,     connectTimeout: 5000,     receiveTimeout: 5000,     headers: {       //预设好的header信息       "testHeader":"bb"     },     contentType: ContentType.json,     responseType: ResponseType.json,   );/<code>

还是上述请求,现在我们重新走一遍上述的get请求,看下log控制台打印的header信息

Flutter  基于网络请求框架Dio的二次封装

然后我修改原先的get请求,给options添加RequestOptions,修改里面的header值如代码所示:

<code>getRequest() async {   var data = {"cid": 60};   RequestOptions requestOptions = new RequestOptions(headers: {"testHeader":"aaaa"});   String result = await DioUtils()       .get('/article/list/0/json', data: data,options: requestOptions);   this.setState(() {     resultJson = result;   }); }/<code>

运行代码,再次执行get请求,控制台的header信息已经被我们修改过了:

Flutter  基于网络请求框架Dio的二次封装

通过RequestOptions不仅仅是可以修改headerl,基本你能在工具类设置的东西都能做修改,感兴趣的读者可以自行阅读源码测试,限于篇幅问题我这里就不展开讲解了。

POST请求封装 POST请求封装跟GET类似,这里我就不过多分析了

利用拦截器给网络请求添加统一参数

在DIo中我们可以通过Interceptors为我们的网络请求添加拦截器

<code>_dio.interceptors.add()/<code>

我们通过_dio.interceptors.add()方法可以根据不同业务为我们的工具类添加不同的拦截器,比如在网络请求开始之前,我们给每个请求都添加统一的token,或者userId,或者我们可以对请求返回的数据做统一json格式化处理,对错误响应统一处理,这些业务场景都可以通过interceptors来完成,比如下面我的配置:

<code>//可根据项目需要选择性的添加请求拦截器    _dio.interceptors.add(      InterceptorsWrapper(onRequest: (RequestOptions requestions) async {        //此处可网络请求之前做相关配置,比如会所有请求添加token,或者userId        requestions.queryParameters["token"] = "testtoken123443423";        requestions.queryParameters["userId"] = "123456";        return requestions;      }, onResponse: (Response response) {        //此处拦截工作在数据返回之后,可在此对dio请求的数据做二次封装或者转实体类等相关操作        return response;      }, onError: (DioError error) {        //处理错误请求        return error;      }),    );  }/<code>

现在我们通过工具类进行的所有的网络请求的url后面都会被加入token=“testtoken123443423”&userId=123456这样两个参数,还是上面的GET请求,下面我们通过代码跟控制台的输出内容看下通过拦截器添加完通用参数的请求,log控制台打印的请求参数信息

<code>getRequest() async {    var data = {"cid": 60};    String result = await DioUtils()        .get('/article/list/0/json', data: data);    this.setState(() {      resultJson = result;    });  }/<code>
Flutter  基于网络请求框架Dio的二次封装

上面的GET请求,我们在参数里只添加了cid = 60的参数,但是通过控制台我们已经清楚的看到token跟userId已经通过拦截器的被我们添加到queryParameters里面了。


分享到:


相關文章: