美文网首页FlutterFlutter开发圈
Flutter 网络请求 Dio 封装

Flutter 网络请求 Dio 封装

作者: Cheney2006 | 来源:发表于2020-03-21 14:22 被阅读0次

      在Flutter项目中使用网络请求的方式大致可分为两种,分别是Dart原生的网络请求 HttpClient类以及第三方开源的网络请求库。在Dart社区开源的第三方http请求库中Flutter中文网开源的Dio库人气最高。

      下面我们先来比较下这两种网络请求方式,然后再看怎么基于 Dio库封装方便使用的网络请求工具类HttpManager。

    网络请求库比较

    HttClient类

    Dart IO库中提供了用于发起Http请求的一些类,我们可以直接使用HttpClient来发起请求。使用HttpClient发起请求分为五步:

    1. 创建一个HttpClient
     HttpClient httpClient = new HttpClient();
    
    1. 打开Http连接,设置请求头
    HttpClientRequest request = await httpClient.getUrl(uri);
    

    这一步可以使用任意Http Method,如httpClient.post(...)、httpClient.delete(...)等。如果包含Query参数,可以在构建uri时添加,如:

    Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: {
        "xx":"xx",
        "yy":"dd"
      });
    

    通过HttpClientRequest可以设置请求header,如:

    request.headers.add("user-agent", "test");
    

    如果是post或put等可以携带请求体方法,可以通过HttpClientRequest对象发送request body,如:

    String payload="...";
    request.add(utf8.encode(payload)); 
    //request.addStream(_inputStream); //可以直接添加输入流
    
    1. 等待连接服务器
    HttpClientResponse response = await request.close();
    

    这一步完成后,请求信息就已经发送给服务器了,返回一个HttpClientResponse对象,它包含响应头(header)和响应流(响应体的Stream),接下来就可以通过读取响应流来获取响应内容。

    1. 读取响应内容
    String responseBody = await response.transform(utf8.decoder).join();
    

    我们通过读取响应流来获取服务器返回的数据,在读取时我们可以设置编码格式,这里是utf8。

    1. 请求结束,关闭HttpClient
    httpClient.close();
    

    关闭client后,通过该client发起的所有请求都会中止。

      以上的步骤是dart原生网络HttpClient使用方式,可以发现直接使用HttpClient发起网络请求是比较麻烦的,很多事情都得手动处理,如果再涉及到文件上传/下载、Cookie管理等就会变得非常繁琐,并且HttpClient本身功能较弱,很多常用功能都不支持。

    Dio库

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

    1. pubspec.yaml 添加依赖
    dependencies:
      dio: ^x.x.x #请使用pub上的最新版本
    
    1. 导入引用并创建dio 实例
    import 'package:dio/dio.dart';
    Dio dio =  Dio();
    

    接下来就可以通过 dio实例来发起网络请求了,注意,一个dio实例可以发起多个http请求,一般来说,APP只有一个http数据源时,dio应该使用单例模式。

    1. 发起网络请求

    Get 请求

    Response response;
    response=await dio.get("/test?id=12&name=cheney")
    print(response.data.toString());
    

    Post请求

    Response response;
    response=await dio.post("/test",data:{"id":12,"name":"cheney"})
    print(response.data.toString());
    

      以上就是Dio库网络请求的基本使用,是不是很简单,除了这些基本的用法,dio还支持请求配置、拦截器等,官方资料比较详细,故在这里不再赘述,详情可以参考dio主页:https://github.com/flutterchina/dio

    封装Dio工具类

    为什么要封装 dio

    做一些公共处理,方便灵活的使用。

    做那些封装

    • 统一处理请求前缀;(https://www.xx.com/api/v1 不用每个请求都加前缀)
    • 统一输出请求或响应信息;
    • 统一错误信息处理;
    • 兼容多种网络请求、支持文件上传、下载;
    • 支持同步回调与异步Future 两种形式
    • 返回数据自动转json格式并默认解析公共数据模型;

    目录

    类名 描述
    HttpManager 网络请求管理类
    HttpError 网络请求统一错误类
    LogInterceptor 网络请求工具类

    HttpManager

    import 'dart:core';
    
    import 'package:connectivity/connectivity.dart';
    import 'package:dio/dio.dart';
    import 'package:flutter/material.dart';
    import 'package:flutter_common_utils/http/http_error.dart';
    import 'package:flutter_common_utils/log_util.dart';
    
    ///http请求成功回调
    typedef HttpSuccessCallback<T> = void Function(dynamic data);
    
    ///失败回调
    typedef HttpFailureCallback = void Function(HttpError data);
    
    ///数据解析回调
    typedef T JsonParse<T>(dynamic data);
    
    
    /// @desc  封装 http 请求
    /// @time 2019/3/15 10:35 AM
    /// @author Cheney
    class HttpManager {
      ///同一个CancelToken可以用于多个请求,当一个CancelToken取消时,所有使用该CancelToken的请求都会被取消,一个页面对应一个CancelToken。
      Map<String, CancelToken> _cancelTokens =  Map<String, CancelToken>();
    
      ///超时时间
      static const int CONNECT_TIMEOUT = 30000;
      static const int RECEIVE_TIMEOUT = 30000;
    
      /// http request methods
      static const String GET = 'get';
      static const String POST = 'post';
    
      Dio _client;
    
      static final HttpManager _instance = HttpManager._internal();
    
      factory HttpManager() => _instance;
    
      Dio get client => _client;
    
      /// 创建 dio 实例对象
      HttpManager._internal() {
        if (_client == null) {
          /// 全局属性:请求前缀、连接超时时间、响应超时时间
          BaseOptions options = BaseOptions(
            connectTimeout: CONNECT_TIMEOUT,
            receiveTimeout: RECEIVE_TIMEOUT,
          );
          _client = Dio(options);
        }
      }
    
      ///初始化公共属性
      ///
      /// [baseUrl] 地址前缀
      /// [connectTimeout] 连接超时赶时间
      /// [receiveTimeout] 接收超时赶时间
      /// [interceptors] 基础拦截器
      void init(
          {String baseUrl,
          int connectTimeout,
          int receiveTimeout,
          List<Interceptor> interceptors}) {
        _client.options = _client.options.merge(
          baseUrl: baseUrl,
          connectTimeout: connectTimeout,
          receiveTimeout: receiveTimeout,
        );
        if (interceptors != null && interceptors.isNotEmpty) {
          _client.interceptors..addAll(interceptors);
        }
      }
    
      ///Get网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[successCallback] 请求成功回调
      ///[errorCallback] 请求失败回调
      ///[tag] 请求统一标识,用于取消网络请求
      void get({
        @required String url,
        Map<String, dynamic> params,
        Options options,
        HttpSuccessCallback successCallback,
        HttpFailureCallback errorCallback,
        @required String tag,
      }) async {
        _request(
          url: url,
          params: params,
          method: GET,
          successCallback: successCallback,
          errorCallback: errorCallback,
          tag: tag,
        );
      }
    
      ///post网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[successCallback] 请求成功回调
      ///[errorCallback] 请求失败回调
      ///[tag] 请求统一标识,用于取消网络请求
      void post({
        @required String url,
        data,
        Map<String, dynamic> params,
        Options options,
        HttpSuccessCallback successCallback,
        HttpFailureCallback errorCallback,
        @required String tag,
      }) async {
        _request(
          url: url,
          data: data,
          method: POST,
          params: params,
          successCallback: successCallback,
          errorCallback: errorCallback,
          tag: tag,
        );
      }
    
      ///统一网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[successCallback] 请求成功回调
      ///[errorCallback] 请求失败回调
      ///[tag] 请求统一标识,用于取消网络请求
      void _request({
        @required String url,
        String method,
        data,
        Map<String, dynamic> params,
        Options options,
        HttpSuccessCallback successCallback,
        HttpFailureCallback errorCallback,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
          }
          LogUtil.v("请求网络异常,请稍后重试!");
          return;
        }
    
        //设置默认值
        params = params ?? {};
        method = method ?? 'GET';
    
        options?.method = method;
    
        options = options ??
            Options(
              method: method,
            );
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          Response<Map<String, dynamic>> response = await _client.request(url,
              data: data,
              queryParameters: params,
              options: options,
              cancelToken: cancelToken);
          String statusCode = response.data["statusCode"];
          if (statusCode == "0") {
            //成功
            if (successCallback != null) {
              successCallback(response.data["data"]);
            }
          } else {
            //失败
            String message = response.data["statusDesc"];
            LogUtil.v("请求服务器出错:$message");
            if (errorCallback != null) {
              errorCallback(HttpError(statusCode, message));
            }
          }
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          if (errorCallback != null && e.type != DioErrorType.CANCEL) {
            errorCallback(HttpError.dioError(e));
          }
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
          }
        }
      }
    
      ///下载文件
      ///
      ///[url] 下载地址
      ///[savePath]  文件保存路径
      ///[onReceiveProgress]  文件保存路径
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[successCallback] 请求成功回调
      ///[errorCallback] 请求失败回调
      ///[tag] 请求统一标识,用于取消网络请求
      void download({
        @required String url,
        @required savePath,
        ProgressCallback onReceiveProgress,
        Map<String, dynamic> params,
        data,
        Options options,
        HttpSuccessCallback successCallback,
        HttpFailureCallback errorCallback,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
          }
          LogUtil.v("请求网络异常,请稍后重试!");
          return;
        }
    
        ////0代表不设置超时
        int receiveTimeout = 0;
        options ??= options == null
            ? Options(receiveTimeout: receiveTimeout)
            : options.merge(receiveTimeout: receiveTimeout);
    
        //设置默认值
        params = params ?? {};
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          Response response = await _client.download(url, savePath,
              onReceiveProgress: onReceiveProgress,
              queryParameters: params,
              data: data,
              options: options,
              cancelToken: cancelToken);
          //成功
          if (successCallback != null) {
            successCallback(response.data);
          }
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          if (errorCallback != null && e.type != DioErrorType.CANCEL) {
            errorCallback(HttpError.dioError(e));
          }
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
          }
        }
      }
    
      ///上传文件
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[onSendProgress] 上传进度
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[successCallback] 请求成功回调
      ///[errorCallback] 请求失败回调
      ///[tag] 请求统一标识,用于取消网络请求
      void upload({
        @required String url,
        FormData data,
        ProgressCallback onSendProgress,
        Map<String, dynamic> params,
        Options options,
        HttpSuccessCallback successCallback,
        HttpFailureCallback errorCallback,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
          }
          LogUtil.v("请求网络异常,请稍后重试!");
          return;
        }
    
        //设置默认值
        params = params ?? {};
    
        //强制 POST 请求
        options?.method = POST;
    
        options = options ??
            Options(
              method: POST,
            );
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          Response<Map<String, dynamic>> response = await _client.request(url,
              onSendProgress: onSendProgress,
              data: data,
              queryParameters: params,
              options: options,
              cancelToken: cancelToken);
          String statusCode = response.data["statusCode"];
          if (statusCode == "0") {
            //成功
            if (successCallback != null) {
              successCallback(response.data["data"]);
            }
          } else {
            //失败
            String message = response.data["statusDesc"];
            LogUtil.v("请求服务器出错:$message");
            if (errorCallback != null) {
              errorCallback(HttpError(statusCode, message));
            }
          }
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          if (errorCallback != null && e.type != DioErrorType.CANCEL) {
            errorCallback(HttpError.dioError(e));
          }
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          if (errorCallback != null) {
            errorCallback(HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
          }
        }
      }
    
      ///GET异步网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[tag] 请求统一标识,用于取消网络请求
      Future<T> getAsync<T>({
        @required String url,
        Map<String, dynamic> params,
        Options options,
        JsonParse<T> jsonParse,
        @required String tag,
      }) async {
        return _requestAsync(
          url: url,
          method: GET,
          params: params,
          options: options,
          jsonParse: jsonParse,
          tag: tag,
        );
      }
    
      ///POST 异步网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[tag] 请求统一标识,用于取消网络请求
      Future<T> postAsync<T>({
        @required String url,
        data,
        Map<String, dynamic> params,
        Options options,
        JsonParse<T> jsonParse,
        @required String tag,
      }) async {
        return _requestAsync(
          url: url,
          method: POST,
          data: data,
          params: params,
          options: options,
          jsonParse: jsonParse,
          tag: tag,
        );
      }
    
      ///统一网络请求
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[tag] 请求统一标识,用于取消网络请求
      Future<T> _requestAsync<T>({
        @required String url,
        String method,
        data,
        Map<String, dynamic> params,
        Options options,
        JsonParse<T> jsonParse,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          LogUtil.v("请求网络异常,请稍后重试!");
          throw (HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
        }
    
        //设置默认值
        params = params ?? {};
        method = method ?? 'GET';
    
        options?.method = method;
    
        options = options ??
            Options(
              method: method,
            );
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          Response<Map<String, dynamic>> response = await _client.request(url,
              queryParameters: params,
              data: data,
              options: options,
              cancelToken: cancelToken);
          String statusCode = response.data["statusCode"];
          if (statusCode == "0") {
            //成功
            if (jsonParse != null) {
              return jsonParse(response.data["data"]);
            } else {
              return response.data["data"];
            }
          } else {
            //失败
            String message = response.data["statusDesc"];
            LogUtil.v("请求服务器出错:$message");
            //只能用 Future,外层有 try catch
            return Future.error((HttpError(statusCode, message)));
          }
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          throw (HttpError.dioError(e));
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          throw (HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
        }
      }
    
      ///异步下载文件
      ///
      ///[url] 下载地址
      ///[savePath]  文件保存路径
      ///[onReceiveProgress]  文件保存路径
      ///[data] post 请求参数
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[tag] 请求统一标识,用于取消网络请求
      Future<Response> downloadAsync({
        @required String url,
        @required savePath,
        ProgressCallback onReceiveProgress,
        Map<String, dynamic> params,
        data,
        Options options,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          LogUtil.v("请求网络异常,请稍后重试!");
          throw (HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
        }
        //设置下载不超时
        int receiveTimeout = 0;
        options ??= options == null
            ? Options(receiveTimeout: receiveTimeout)
            : options.merge(receiveTimeout: receiveTimeout);
    
        //设置默认值
        params = params ?? {};
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          return _client.download(url, savePath,
              onReceiveProgress: onReceiveProgress,
              queryParameters: params,
              data: data,
              options: options,
              cancelToken: cancelToken);
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          throw (HttpError.dioError(e));
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          throw (HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
        }
      }
    
      ///上传文件
      ///
      ///[url] 网络请求地址不包含域名
      ///[data] post 请求参数
      ///[onSendProgress] 上传进度
      ///[params] url请求参数支持restful
      ///[options] 请求配置
      ///[tag] 请求统一标识,用于取消网络请求
      Future<T> uploadAsync<T>({
        @required String url,
        FormData data,
        ProgressCallback onSendProgress,
        Map<String, dynamic> params,
        Options options,
        JsonParse<T> jsonParse,
        @required String tag,
      }) async {
        //检查网络是否连接
        ConnectivityResult connectivityResult =
            await (Connectivity().checkConnectivity());
        if (connectivityResult == ConnectivityResult.none) {
          LogUtil.v("请求网络异常,请稍后重试!");
          throw (HttpError(HttpError.NETWORK_ERROR, "网络异常,请稍后重试!"));
        }
    
        //设置默认值
        params = params ?? {};
    
        //强制 POST 请求
        options?.method = POST;
    
        options = options ??
            Options(
              method: POST,
            );
    
        url = _restfulUrl(url, params);
    
        try {
          CancelToken cancelToken;
          if (tag != null) {
            cancelToken =
                _cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
            _cancelTokens[tag] = cancelToken;
          }
    
          Response<Map<String, dynamic>> response = await _client.request(url,
              onSendProgress: onSendProgress,
              data: data,
              queryParameters: params,
              options: options,
              cancelToken: cancelToken);
    
          String statusCode = response.data["statusCode"];
          if (statusCode == "0") {
            //成功
            if (jsonParse != null) {
              return jsonParse(response.data["data"]);
            } else {
              return response.data["data"];
            }
          } else {
            //失败
            String message = response.data["statusDesc"];
            LogUtil.v("请求服务器出错:$message");
            return Future.error((HttpError(statusCode, message)));
          }
        } on DioError catch (e, s) {
          LogUtil.v("请求出错:$e\n$s");
          throw (HttpError.dioError(e));
        } catch (e, s) {
          LogUtil.v("未知异常出错:$e\n$s");
          throw (HttpError(HttpError.UNKNOWN, "网络异常,请稍后重试!"));
        }
      }
    
      ///取消网络请求
      void cancel(String tag) {
        if (_cancelTokens.containsKey(tag)) {
          if (!_cancelTokens[tag].isCancelled) {
            _cancelTokens[tag].cancel();
          }
          _cancelTokens.remove(tag);
        }
      }
    
      ///restful处理
      String _restfulUrl(String url, Map<String, dynamic> params) {
        // restful 请求处理
        // /gysw/search/hist/:user_id        user_id=27
        // 最终生成 url 为     /gysw/search/hist/27
        params.forEach((key, value) {
          if (url.indexOf(key) != -1) {
            url = url.replaceAll(':$key', value.toString());
          }
        });
        return url;
      }
    }
    
    

    这里处理了网络连接判断、取消网络请求、默认的数据格式解析等。
    默认解析的数据格式:

    {
        "data":{},
        "statusCode":"0",
        "statusDesc":"02032008:用户授信未通过",
        "timestamp":1569206576392
    }
    

    大家可根据自己的需求更改成自己的数据格式处理

    HttpError

    import 'package:dio/dio.dart';
    
    /// @desc  网络请求错误
    /// @time 2019/3/20 10:02 AM
    /// @author Cheney
    class HttpError {
      ///HTTP 状态码
      static const int UNAUTHORIZED = 401;
      static const int FORBIDDEN = 403;
      static const int NOT_FOUND = 404;
      static const int REQUEST_TIMEOUT = 408;
      static const int INTERNAL_SERVER_ERROR = 500;
      static const int BAD_GATEWAY = 502;
      static const int SERVICE_UNAVAILABLE = 503;
      static const int GATEWAY_TIMEOUT = 504;
    
      ///未知错误
      static const String UNKNOWN = "UNKNOWN";
    
      ///解析错误
      static const String PARSE_ERROR = "PARSE_ERROR";
    
      ///网络错误
      static const String NETWORK_ERROR = "NETWORK_ERROR";
    
      ///协议错误
      static const String HTTP_ERROR = "HTTP_ERROR";
    
      ///证书错误
      static const String SSL_ERROR = "SSL_ERROR";
    
      ///连接超时
      static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
    
      ///响应超时
      static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";
    
      ///发送超时
      static const String SEND_TIMEOUT = "SEND_TIMEOUT";
    
      ///网络请求取消
      static const String CANCEL = "CANCEL";
    
      String code;
    
      String message;
    
      HttpError(this.code, this.message);
    
      HttpError.dioError(DioError error) {
        message = error.message;
        switch (error.type) {
          case DioErrorType.CONNECT_TIMEOUT:
            code = CONNECT_TIMEOUT;
            message = "网络连接超时,请检查网络设置";
            break;
          case DioErrorType.RECEIVE_TIMEOUT:
            code = RECEIVE_TIMEOUT;
            message = "服务器异常,请稍后重试!";
            break;
          case DioErrorType.SEND_TIMEOUT:
            code = SEND_TIMEOUT;
            message = "网络连接超时,请检查网络设置";
            break;
          case DioErrorType.RESPONSE:
            code = HTTP_ERROR;
            message = "服务器异常,请稍后重试!";
            break;
          case DioErrorType.CANCEL:
            code = CANCEL;
            message = "请求已被取消,请重新请求";
            break;
          case DioErrorType.DEFAULT:
            code = UNKNOWN;
            message = "网络异常,请稍后重试!";
            break;
        }
      }
    
      @override
      String toString() {
        return 'HttpError{code: $code, message: $message}';
      }
    }
    
    

    这里设置了多种错误的描述,大家可根据需求修改。

    LogInterceptor

    import 'package:dio/dio.dart';
    import 'package:flutter_common_utils/log_util.dart';
    
    void log2Console(Object object) {
      LogUtil.v(object);
    }
    
    /// @desc  自定义日志拦截器
    ///@time 2019/3/18 9:15 AM
    /// @author Cheney
    class LogInterceptor extends Interceptor {
      LogInterceptor({
        this.request = true,
        this.requestHeader = true,
        this.requestBody = false,
        this.responseHeader = true,
        this.responseBody = false,
        this.error = true,
        this.logPrint = log2Console,
      });
    
      /// Print request [Options]
      bool request;
    
      /// Print request header [Options.headers]
      bool requestHeader;
    
      /// Print request data [Options.data]
      bool requestBody;
    
      /// Print [Response.data]
      bool responseBody;
    
      /// Print [Response.headers]
      bool responseHeader;
    
      /// Print error message
      bool error;
    
      /// Log printer; defaults print log to console.
      /// In flutter, you'd better use debugPrint.
      /// you can also write log in a file, for example:
      ///```dart
      ///  var file=File("./log.txt");
      ///  var sink=file.openWrite();
      ///  dio.interceptors.add(LogInterceptor(logPrint: sink.writeln));
      ///  ...
      ///  await sink.close();
      ///```
      void Function(Object object) logPrint;
    
      @override
      Future onRequest(RequestOptions options) async {
        logPrint('*** Request ***');
        printKV('uri', options.uri);
    
        if (request) {
          printKV('method', options.method);
          printKV('responseType', options.responseType?.toString());
          printKV('followRedirects', options.followRedirects);
          printKV('connectTimeout', options.connectTimeout);
          printKV('receiveTimeout', options.receiveTimeout);
          printKV('extra', options.extra);
        }
        if (requestHeader) {
          logPrint('headers:');
          options.headers.forEach((key, v) => printKV(" $key", v));
        }
        if (requestBody) {
          logPrint("data:");
          printAll(options.data);
        }
        logPrint("");
      }
    
      @override
      Future onError(DioError err) async {
        if (error) {
          logPrint('*** DioError ***:');
          logPrint("uri: ${err.request.uri}");
          logPrint("$err");
          if (err.response != null) {
            _printResponse(err.response);
          }
          logPrint("");
        }
      }
    
      @override
      Future onResponse(Response response) async {
        logPrint("*** Response ***");
        _printResponse(response);
      }
    
      void _printResponse(Response response) {
        printKV('uri', response.request?.uri);
        if (responseHeader) {
          printKV('statusCode', response.statusCode);
          if (response.isRedirect == true) {
            printKV('redirect', response.realUri);
          }
          if (response.headers != null) {
            logPrint("headers:");
            response.headers.forEach((key, v) => printKV(" $key", v.join(",")));
          }
        }
        if (responseBody) {
          logPrint("Response Text:");
          printAll(response.toString());
        }
        logPrint("");
      }
    
      printKV(String key, Object v) {
        logPrint('$key: $v');
      }
    
      printAll(msg) {
        msg.toString().split("\n").forEach(logPrint);
      }
    }
    
    

    这里默认使用 LogUtl 输出日志,大家可根据需要换成自己的日志输出工具类

    使用示例

    image

    Step1: 初始化

    //初始化 Http,
      HttpManager().init(
        baseUrl: Api.getBaseUrl(),
        interceptors: [
          HeaderInterceptor(),
          LogInterceptor(),
        ],
      );
    

    Step2:创建网络请求

    ///同步回调模式
    ///get 网络请求
    void _get(){
       HttpManager().get(
          url: "/app/info",
          params: {"iouCode": iouCode},
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
           
          },
          tag: "tag",
        );
    }
    ///post 网络请求
    void _post(){
         HttpManager().post(
          url: "/app/info",
          data: {"iouCode": iouCode},
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
            
          },
          tag: "tag",
        );
    }
    
    ///下载文件
    void _download(){
         HttpManager().download(
          url: "/app/download",
          savePath: "/savePath",
          onReceiveProgress: (int count, int total) {
          },
          successCallback: (data) {
            
          },
          errorCallback: (HttpError error) {
            
          },
          tag: tag,
        );
    }
    
    ///上传文件
    void _upload() async{
    FormData data = FormData.fromMap({
            "file": await MultipartFile.fromFile(path, filename: "$photoTime"),
          });
        HttpManager().upload(
            url: "/app/upload",
            data: data,
            tag: "tag",
            successCallback: (data) {
              
            },
            errorCallback: (HttpError error) {
              
            },
          );
    }
    
    
    ///异步模式
    ///get 请求
    void _getAysnc() async{
         String timestamp =
            await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
    }
    
    ///post 请求
    void _postAysnc() async{
       await HttpManager().postAsync(
            url: "app/info",
            tag: "tag",
            data: {
              'bannerTypes': ["wealthBanner"],
            },
            jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
    }
    
    ///下载文件
    void _downloadAsync() async{
        await HttpManager().downloadAsync(
          url: "/app/download",
          savePath: "/savePath",
          onReceiveProgress: (int count, int total) {
          },
          tag: "tag",
        );
    }
    
    ///上传文件
    void _uploadAsync() async{
    FormData data = FormData.fromMap({
            "file": await MultipartFile.fromFile(path, filename: "$photoTime"),
          });
      await  HttpManager().uploadAsync(
            url: "/app/upload",
            data: data,
            tag: "tag",
           
          );
    }
    

    最后

      如果在使用过程遇到问题,欢迎下方留言交流。

      工具类库地址

    学习资料

    请大家不吝点赞!因为您的点赞是对我最大的鼓励,谢谢!

    相关文章

      网友评论

        本文标题:Flutter 网络请求 Dio 封装

        本文链接:https://www.haomeiwen.com/subject/qpvyyhtx.html