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裡面了。


分享到:


相關文章: