Flutter 开发 Http dio 网络库的封装以及使用

配置

  • 1、打开项目中 pubspec.yaml 文件

  • 2、找到 dependencies (第三方框架管理)

    在 dependencies 下面添加 dio: ^1.0.0dio: 1.0.0(具体格式:name:^+version),如下图所示

pubspec dependencies

封装

  • http_utils - A HTTP tool to receive data, download and upload files, etc.

Next, the source code is shown as follows:

//
// Created by dyf on 2018/9/3.
// Copyright (c) 2018 dyf.
//

import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';

export 'package:dio/dio.dart';
export 'dart:io';

// ===============================================
// Response callbacks the http info.
// ===============================================

/// When data is received, it is called.
typedef void OnResponseSuccess(Response response);

/// When the request fails, it is called.
typedef void OnResponseError(DioError error);


/// Defines a HTTP tool to receive data, download and upload files, etc.
class HttpUtils {
  /// Request base url, it can contain sub path, like: "https://www.google.com/api/".
  String baseUrl;

  /// Timeout in seconds for opening url.
  int connectTimeout;

  /// This is not the receiving time limitation, in seconds.
  int receiveTimeout;

  /// Http request headers.
  Map<String, dynamic> headers;

  /// The request Content-Type. The default value is [ContentType.json].
  /// If you want to encode request body with "application/x-www-form-urlencoded",
  /// you can set `ContentType.parse("application/x-www-form-urlencoded")`, and [Dio]
  /// will automatically encode the request body.
  ContentType contentType;

  /// Cookie manager for http requests。Learn more details about
  /// CookieJar please refer to [cookie_jar](https://github.com/flutterchina/cookie_jar)
  CookieJar cookieJar;

  /// A powerful Http client.
  Dio _dio;

  /// You can cancel a request by using a cancel token.
  CancelToken _cancelToken;

  /// Each Dio instance has a interceptor by which you can intercept requests or responses before they are
  /// handled by `then` or `catchError`. the [interceptor] field
  /// contains a [RequestInterceptor] and a [ResponseInterceptor] instance.
  Interceptor get interceptor => _dio.interceptor;

  /// If the `url` starts with "http(s)", the `baseURL` will be ignored, otherwise,
  /// it will be combined and then resolved with the baseUrl.
  String url = "";

  /// Success response callback.
  OnResponseSuccess _onSuccess;

  /// Failure response callback.
  OnResponseError _onError;

  /// Constructor
  HttpUtils({
    this.baseUrl,
    this.connectTimeout: 0,
    this.receiveTimeout: 0,
    this.headers,
    this.contentType,
    this.cookieJar
  });

  /// Named constructor
  HttpUtils.config({
    String baseUrl,
    int connectTimeout: 0,
    int receiveTimeout: 0,
    Map<String, dynamic> headers,
    ContentType contentType,
    CookieJar cookieJar
  }) : connectTimeout = 0,
       receiveTimeout = 0 {
    if (baseUrl != null) {
      this.baseUrl = baseUrl;
    }
    if (connectTimeout > 0) {
      this.connectTimeout = connectTimeout;
    }
    if (receiveTimeout > 0) {
      this.receiveTimeout = receiveTimeout;
    }
    if (headers != null) {
      this.headers = headers;
    }
    if (contentType != null) {
      this.contentType = contentType;
    }
    if (cookieJar != null) {
      this.cookieJar = cookieJar;
    }
  }

  void _init() {
    _cancelToken = new CancelToken();
    // Create Dio instance with default [Options].
    _dio = new Dio();
  }

  void _mergeOptions() {
    if (baseUrl != null) {
      _dio.options.baseUrl = baseUrl;
    }
    if (connectTimeout > 0) {
      _dio.options.connectTimeout = 1000 * connectTimeout;
    }
    if (receiveTimeout > 0) {
      _dio.options.receiveTimeout = 1000 * receiveTimeout;
    }
    if (headers != null) {
      _dio.options.headers = headers;
    }
    if (contentType != null) {
      _dio.options.contentType = contentType;
    }
  }

  String _checkPath(String path) {
    if (baseUrl != null && baseUrl.isNotEmpty && path.contains(baseUrl)) {
      url = path;
    } else {
      url = (baseUrl ?? "") + path;
    }
    return url;
  }

  void _checkCookie() {
    if (cookieJar != null) {
      _dio.cookieJar = cookieJar;
    }
  }

  /// Callback to listen the http info.
  void listen(OnResponseSuccess onSuccess, OnResponseError onError) {
    _onSuccess = onSuccess;
    _onError = onError;
  }

  /// Handy method to make http GET request.
  void get(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);
      var response;
      if (data != null) {
        response = await _dio.get(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.get(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http POST request.
  void post(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);
      var response;
      if (data != null) {
        response = await _dio.post(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.post(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http PUT request.
  void put(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);
      var response;
      if (data != null) {
        response = await _dio.put(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.put(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http HEAD request.
  void head(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);

      var response;
      if (data != null) {
        response = await _dio.head(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.head(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http DELETE request.
  void delete(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);

      var response;
      if (data != null) {
        response = await _dio.delete(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.delete(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http PATCH request.
  void patch(String path, {data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);

      var response;
      if (data != null) {
        response = await _dio.patch(url, data: data, cancelToken: _cancelToken);
      } else {
        response = await _dio.patch(url, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Download the file and save it in local. The default http method is "GET".
  void download(String path, String savePath, {OnDownloadProgress onProgress, data}) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);

      var response;
      if (data != null) {
        response = await _dio.download(url, savePath,
            onProgress: onProgress, cancelToken: _cancelToken, data: data);
      } else {
        response = await _dio.download(url, savePath,
            onProgress: onProgress, cancelToken: _cancelToken);
      }

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Handy method to make http POST request.
  /// [UploadFileInfo] Describes the info of file to upload,
  /// e.g.: UploadFileInfo(new File("./example/upload.txt"), "upload.txt").
  void upload(String path, Map<String, dynamic> data) async {
    try {
      _init();
      _mergeOptions();
      _checkCookie();

      var url = _checkPath(path);

      FormData formData = new FormData.from(data);
      var response =
          await _dio.post(url, data: formData, cancelToken: _cancelToken);

      if (_onSuccess != null) _onSuccess(response);
    } on DioError catch (e) {
      if (_onError != null) _onError(e);
    }
  }

  /// Cancel the request.
  void cancel() {
    _cancelToken.cancel();
  }
}

使用示例

  • HttpUtils 示例
class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  String _data = "";

  void _getTokenData() {
    var baseUrl = "https://etherscan.io";
    var httpUtils = new HttpUtils.config(baseUrl: baseUrl);
    httpUtils.connectTimeout = 10;
    // httpUtils.contentType = ContentType.html;
    // 0x71c7656ec7ab88b098defb751b7401b5f6d8976f
    httpUtils.get("/address/0x71c7656ec7ab88b098defb751b7401b5f6d8976f");
    print("url: ${httpUtils.url}");
    httpUtils.listen((Response response) {
      String data = response.data;
      //print("data: $data");
      setState(() {
        _data = data;
      });
    }, (DioError error) {
      print("e: ${error.message}");
    });
  }

  void _getTokenholdingsData() async {
    String a = "0x71c7656ec7ab88b098defb751b7401b5f6d8976f";
    String data = await EthTokenholdingsDataRequest.init(a).getData();
    if (data != null && data.isNotEmpty) {
      EthTokenholdingsParser.parse(data, a);
    }
  }

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

  void _incrementCounter() {
    if (_data.isNotEmpty) {
      EthTokenParser.parse(_data).then<bool>((finished){
        if (finished) {
          Navigator.push(context, _createPushRoute());
        }
      });
    } else {
      print("data is empty.");
    }
  }

  MaterialPageRoute _createPushRoute() {
    return MaterialPageRoute(builder: (context) => 
      new EthTokensDisplayView("0x71c7656ec7ab88b098defb751b7401b5f6d8976f")
    );
  }

  @override
  Widget build(BuildContext context) {

    return new Scaffold(
      appBar: new AppConfigurator('UI').createAppBar(
        title: new Text(widget.title, style: new TextStyle(fontSize: 18.0),)
      ),
     
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              'You have pushed the button this many times:',
            ),
            new Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
          ],
        ),
      ),
      floatingActionButton: new FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: new Icon(Icons.add),
      ), 
    );
  }
}
  • dio 示例
//
// Created by dyf on 2018/9/7.
// Copyright (c) 2018 dyf.
//

import 'dart:async';

import 'package:dio/dio.dart';
import 'package:html/parser.dart' as html;

import './HtmlConverter.dart';
import './ExtendedUtility.dart';

class EthTokenholdingsDataRequest {
  String _address;

  EthTokenholdingsDataRequest(String address) {
    _address = address;
  }

  EthTokenholdingsDataRequest.init(String address)
   : this(address);

  int _getCount(String input) {
    return ExtendedString(input).toInt();
  }

  int _getRow(String input) {
    var dom = html.parse(input);
    List tbodyList = dom.getElementsByTagName("tr");
    return tbodyList.length;
  }

  int _getTotalPage(int count, int row) {
    double doub = count / row;
    int page = count ~/ row;
    if (doub > page) {
      page += 1;
    }
    return page;
  }

  String _getUrl(int page) {
    String baseUrl = "https://etherscan.io";
    var a = "&a=" + _address;
    var q = "&q=";
    var p = "&p=$page";
    var f = "&f=";
    var h = "&h=";
    var fav = "&fav=";
    var s = "&sort=total_price_usd";
    var o = "&order=desc";
    var url = baseUrl + "/tokenholdingsHandler.ashx?" + a + q + p + f + h + fav + s + o;
    return url;
  }

  String _convertToHtml(String input) {
    return new HtmlConverter.init(input).convert(isTable: true);
  }

  Future<dynamic> _doDataRequest(int p) async {
    try {
      var dio = new Dio();
      dio.options.connectTimeout = 5*1000;
      var url = _getUrl(p);
      print("url: $url");
      Response response = await dio.get(url); 
      return response;
    } on DioError catch(e) {
      return e;
    }
  }

  Future<String> getData() async {
    var ret = await _doDataRequest(1);
    if (ret is Response) {
      var data = ret.data;
      if (data != null && data is Map && data.isNotEmpty) {  
        var records = data["recordsfound"];
        
        int count = _getCount(records);
        if (count > 0) {
          var tbody = data["layout"];
          int row = _getRow(_convertToHtml(tbody));
          int page = _getTotalPage(count, row);
          
          String allData = await _getOtherData(tbody, page);
          return _convertToHtml(allData);
        }
      }
    } else {
      print("e: ${ret.toString()}");
    }

    return null;
  }

  Future<String> _getOtherData(String baseData, int p) async {
    String retData = baseData; 
  
    for (int i = 2; i < p + 1; i++) {
      var ret = await _doDataRequest(i);
      if (ret is Response) {
        var data = ret.data;
        if (data is Map) {
          var tbody = data["layout"];
          retData += tbody;
        }
      } else {
        print("e: ${ret.toString()}");
      }
    }

    return retData;
  }
}

写的有不好的地方希望大家指出,我会更正,大家有什么看不明白的,也可以在评论里面提问,我会尽力解答。


点赞+关注,第一时间获取技术干货和最新知识点,谢谢你的支持!

最后祝大家生活愉快~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,710评论 4 376
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,839评论 2 308
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,295评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,776评论 0 223
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,198评论 3 297
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,074评论 1 226
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,200评论 2 322
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,986评论 0 214
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,733评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,877评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,348评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,675评论 3 265
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,393评论 3 246
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,209评论 0 9
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,996评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,212评论 2 287
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 36,003评论 2 280