Flutter入門進階之旅(十七)Flutter dio網絡請求

前言

前面關於Flutter的講解部分我把關於flutter的基礎入門部分帶着你們梳理了一遍,那從本篇博客開始,咱們開始進入新的領域,也算是給進階篇開個頭,今天咱們來一塊學習一下Flutter中的網絡請求庫--->Dio,關於Flutter原生帶的Http使用起來不論在功能上仍是擴展上都不是那麼的強大,鑑於此筆者在這裏推薦你們在項目中使用Dio封裝網絡請求庫。關於Http的使用讀者可自行查閱資料學習。java

課程目標

  • 使用Dio完成最簡單的GET、POST請求
  • 基於Dio封裝網絡請求庫,並使用本身封裝的網絡請求工具類完成GET、POST請求
  • 瞭解InterceptorsWrapper攔截器
  • 利用攔截器給網絡請求添加統一參數(如,token,userId等)
  • 統一處理響應返回數據(作json轉實體或者格式化操做)
  • 操做請求統一攔截
1.使用Dio完成簡單的GET、POST請求

1.1使用dio get請求一條json數據android

getRequest() async {
    Response response = await Dio() .get('https://www.wanandroid.com/banner/json');
    this.setState(() {
      result= response.toString();
    });
  }
複製代碼

1.2 利用dio post請求註冊一個新用戶git

postRequest() async {
    var path = "https://www.wanandroid.com/user/register";
    var params = {
      "username": "aa112233",
      "password": "123456",
      "repassword": "123456"
    };
    Response response =
        await Dio().post(path, queryParameters: params);
    this.setState(() {
      result= response.toString();
    });
  }
複製代碼

因爲簡單的GET、跟POST請求操做起來比較簡單,我就不單獨附效果圖跟講解說明了,相信讀者從開始看系列博客到如今,讀懂上面的代碼已經不在話下了,我把上面的get、跟post請求放到一張效果圖上代碼也貼到一塊供你們讀閱,另外感謝玩安卓提供的開放API做爲本篇博客的請求測試用例。github

效果圖 json

在這裏插入圖片描述
代碼

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';

class NetWorkPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => PageState();
}

class PageState extends State<NetWorkPage> {
  var resultJson = "";

  @override
  void initState() {
    super.initState();
  }

  getRequest() async {
    Response response = await Dio() .get('https://www.wanandroid.com/banner/json');
    this.setState(() {
      resultJson = response.toString();
    });
  }

  postRequest() async {
    var path = "https://www.wanandroid.com/user/register";
    var params = {
      "username": "aa112233",
      "password": "123456",
      "repassword": "123456"
    };
    Response response =
        await Dio().post(path, queryParameters: params);
    this.setState(() {
      resultJson = response.toString();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Dio網絡請求"),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          MaterialButton(
              color: Colors.pinkAccent,
              child: Text("GET 請求"),
              onPressed: () {
                getRequest();
              }),
          MaterialButton(
              color: Colors.blueAccent,
              child: Text("POST 請求"),
              onPressed: () {
                postRequest();
              }),
          Expanded(
              child: Padding(
            padding: EdgeInsets.all(20),
            child: Center(
              child: resultJson.length <= 0
                  ? Text("數據加載中...")
                  : Text(
                      resultJson,
                      style: TextStyle(fontSize: 16),
                    ),
            ),
          ))
        ],
      ),
    );
  }
}
複製代碼
2.封裝本身的Dio網絡請求庫

在項目開發過程當中隨着項目越寫越大,代碼量也會成倍的增長,隔離業務抽取共性代碼的思想天然而然的出如今一個嚴於律己的開發者腦子裏,特別是像網絡請求這種操做,好的封裝不只會減小冗餘代碼更能讓代碼層級變得清晰可讀,下面筆者就帶着本身的理解對Dio作一個簡單封裝,筆者自認爲才疏學淺,代碼中若有寫的很差的地方還請各位不吝賜教。cookie

通常咱們在處理工具類時都會用到單例的思想,作爲一個項目全局的網絡請求工具類,咱們一樣也把DioUtils封裝成單例模式網絡

static DioUtils getInstance() {
    if (_instance == null) {
      _instance = new DioUtils();
    }
    return _instance;
  }
複製代碼

對於請求參數的初始化跟一些網絡配置,Dio爲開發者提供了BaseOptions、Options、RequestOptions可選Options配置,三者的優先級關係依次遞增app

試想這樣一個場景:通常咱們在對網絡請求工具類設置參數,理論上是全局不能修改的,若是咱們的業務需求必須讓咱們修改配置參數,好比基於不一樣的接口服務須要設置不一樣請求中的header內容,這個時候利用options的優先級咱們就能夠很輕鬆的處理這個問題,稍後我會在代碼裏具體講解async

先來看下BaseOptions給咱們提供的可供配置的參數:ide

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

上面構造方法中的屬性讀者基本都能見名知意作到自解釋,我就不單獨解釋了,貼上一段我在代碼裏的配置:

//請求參數配置
   _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實例中完成配置的初始化

//建立dio實例
    _dio = new Dio(_baseOptions);
複製代碼

接下來我把咱們開篇用DIO作的簡單GET、POST方法用咱們新寫的工具類封裝完成後從新作請求,讓咱們來一塊兒感覺下封裝帶來的便利。

封裝GET請求

/** * 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;
  }
複製代碼

利用咱們封裝好的get請求方法,開篇的get請求只需改成:

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

複製代碼

或者get的時候須要攜帶參數,例如以下這樣一個請求

www.wanandroid.com/article/lis… 方法:GET 參數:cid 分類的id,上述二級目錄的id

對上面的url進行分析

baseUrlwww.wanandroid.com 咱們已經在工具類中初始化過了,因此不用設置 path: /article/list/0/json 咱們在get請求中須要傳入的url data:cid=60 咱們封裝好的get請求中對應的data數據

上述請求爲:

getRequest() async {
    var data = {
      "cid": 60
    };
    String result = await DioUtils().get('/article/list/0/json', data: data);
    this.setState(() {
      resultJson = result;
    });
  }

複製代碼

在剛剛講BaseOptions時,咱們提到還有Options、RequestOptions可供配置,咱們提到能夠利用Options的優先級從新覆蓋掉原先在工具類裏設置好的網絡配置,好比修改提早在header中設置好的請求內容。 仍是上述代碼,我先修改_baseOptions中的header的配置以下:

咱們利用Options修改BaseUrl後的請求url

_baseOptions = new BaseOptions(
     baseUrl: BASE_URL,
     connectTimeout: 5000,
     receiveTimeout: 5000,
     headers: {
       //預設好的header信息
       "testHeader":"bb"
     },
     contentType: ContentType.json,
     responseType: ResponseType.json,
   );
複製代碼

仍是上述請求,如今咱們從新走一遍上述的get請求,看下log控制檯打印的header信息

在這裏插入圖片描述
而後我修改原先的get請求,給options添加RequestOptions,修改裏面的header值如代碼所示:

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;
   });
 }
複製代碼

運行代碼,再次執行get請求,控制檯的header信息已經被咱們修改過了:

在這裏插入圖片描述

筆者只不過是借用這個例子讓讀者瞭解怎麼去修改工具類裏配置好的參數,經過RequestOptions不只僅是能夠修改headerl,基本你能在工具類設置的東西都能作修改,感興趣的讀者能夠自行閱讀源碼測試,限於篇幅問題我這裏就不展開講解了。

POST請求封裝 POST請求封裝跟GET相似,這裏我就不過多分析了,我直接貼源碼了讀者可結合代碼自行對比差別

postRequest() async {
    var params = {
      "username": "aa112233",
      "password": "123456",
      "repassword": "123456"
    };
    String result = await DioUtils().post("/user/register",data: params);
    this.setState(() {
      resultJson = result;
    });
  }
複製代碼
3.利用攔截器給網絡請求添加統一參數

在DIo中咱們能夠經過Interceptors爲咱們的網絡請求添加攔截器

_dio.interceptors.add()
複製代碼

咱們經過_dio.interceptors.add()方法能夠根據不一樣業務爲咱們的工具類添加不一樣的攔截器,好比在網絡請求開始以前,咱們給每一個請求都添加統一的token,或者userId,或者咱們能夠對請求返回的數據作統一json格式化處理,對錯誤響應統一處理,這些業務場景均可以經過interceptors來完成,好比下面個人配置:

//可根據項目須要選擇性的添加請求攔截器
    _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;
      }),
    );
  }
複製代碼

如今咱們經過工具類進行的全部的網絡請求的url後面都會被加入token=「testtoken123443423」&userId=123456這樣兩個參數,仍是上面的GET請求,下面咱們經過代碼跟控制檯的輸出內容看下經過攔截器添加完通用參數的請求,log控制檯打印的請求參數信息

getRequest() async {
    var data = {"cid": 60};
    String result = await DioUtils() .get('/article/list/0/json', data: data);
    this.setState(() {
      resultJson = result;
    });
  }
複製代碼

在這裏插入圖片描述
上面的GET請求,咱們在參數裏只添加了 cid = 60的參數,可是經過控制檯咱們已經清楚的看到token跟userId已經經過攔截器的被咱們添加到 queryParameters裏面了。

限於篇幅問題,封裝好的DioUtils我就不貼出來了,附上源碼的github地址,供讀者參考,最後感謝玩安卓開放API平臺提供的測試API用於本篇博客中的測試用例。

相關文章
相關標籤/搜索