Flutter网络请求dio简易封装

2022-04-22  本文已影响0人  禄子_c79b

DioManager

///    date   : 2021/7/11
///    desc   : 网络请求类

///成功回调
typedef Success<T> = Function(T? data);

///失败回调,若传空,则系统吐司提示,若不会空,自行处理错误结果
typedef Fail = Function(int? code, String? msg);

class DioManager {
  /// 默认code--返回成功
  static const RESP_OK = 200;

  /// 默认code--40001未登录,40002token失效,40010账号被异地登录,40011token来源异常
  static const List RESP_LOGIN_EXPIRE = [40001, 40002, 40010, 40011];

  String? signKey;

  Dio dio = new Dio();
  static DioManager? _instance;

  static DioManager getInstance() {
    if (_instance == null) {
      _instance = new DioManager();
      _instance!._init();
    }
    return _instance!;
  }

  void _init() {
    dio.options.baseUrl = "https://www.fastmock.site/mock/6d5084df89b4c7a49b28052a0f51c29a/test/";
    dio.options.connectTimeout = 5000;
    dio.options.receiveTimeout = 5000;
    dio.options.responseType = ResponseType.json;
    dio.interceptors.add(HeaderInterceptor()); //请求头拦截器
    dio.interceptors.add(DioLogInterceptor()); //是否开启请求日志
    // dio.interceptors.add(ResponseInterceptor()); //请求结果回调
  }

  void setBaseUrl(String baseUrl) {
    dio.options.baseUrl = baseUrl;
  }

  void setSignKey(String signKey) => this.signKey = signKey;

  void setHeader(Map<String, dynamic>? headers) {
    dio.options.headers = headers;
  }

  ///post form 表单提交操作
  Future postForm<T>(
    String path, {
    SplayTreeMap<String, dynamic>? params,
    required Success<T> success,
    required Fail? fail,
    bool withLoading = true,
  }) async {
    var splayTreeMap = new SplayTreeMap<String, dynamic>();
    if (params != null) {
      splayTreeMap.addAll(params);
    }

    if (withLoading) {
      // ToastUtils.getInstance().showLoading();
    }
    try {
      var response = await dio.post(path, data: FormData.fromMap(splayTreeMap));
      parseResponse(response, success, fail);
    } on DioError catch (e) {
      formatError(e, fail);
    }
  }

  ///post json
  Future postJson<T>(
    String path, {
    SplayTreeMap<String, dynamic>? params,
    required Success<T> success,
    required Fail? fail,
    bool withLoading = true,
  }) async {
    var splayTreeMap = new SplayTreeMap<String, dynamic>();
    if (params != null) {
      splayTreeMap.addAll(params);
    }
    if (withLoading) {
      // ToastUtils.getInstance().showLoading();
    }
    try {
      var response = await dio.post(path, data: splayTreeMap);
      parseResponse(response, success, fail);
      print('你好============response11${response}');

    } on DioError catch (e) {
      formatError(e, fail);
    }
  }

  ///get
  Future get<T>(
    String path, {
    SplayTreeMap<String, dynamic>? params,
    required Success<T> success,
    required Fail? fail,
    bool withLoading = true,
  }) async {
    var splayTreeMap = new SplayTreeMap<String, dynamic>();
    if (params != null) {
      splayTreeMap.addAll(params);
    }

    if (withLoading) {
      // ToastUtils.getInstance().showLoading();
    }
    try {
      var response = await dio.get(path, queryParameters: splayTreeMap);
      parseResponse(response, success, fail);
    } on DioError catch (e) {
      formatError(e, fail);
    }
  }

  void parseResponse<T>(
      Response<dynamic> response, Success<T> success, Fail? fail) {
    // ToastUtils.getInstance().hideLoading();
    if (response.statusCode == 200) {
      Map<String, dynamic> result = response.data;
      if (result["code"] == RESP_OK) {
        success(result["data"]);
        return;
      }
      if (RESP_LOGIN_EXPIRE.contains(result["code"])) {
        //登录过期需要重新登录
        // ToastUtils.getInstance().toastFail(result["msg"]);
        // NativeUtils.sendNativeData(NativeUtils.NATIVE_LOGIN);
        return;
      }
      if (fail != null) {
        // fail(result["code"], result["msg"]);
        fail(result["code"], result["message"]);
      } else {
        // ToastUtils.getInstance().toastFail(result["msg"] ?? '');
      }
    } else {
      if (fail != null) {
        fail(response.statusCode ?? -1, response.statusMessage ?? 'error');
      } else {
        // ToastUtils.getInstance().toastFail(response.statusMessage ?? 'error');
      }
    }
  }

  void formatError(DioError e, Fail? fail) {
    print(e.stackTrace);
    if (fail != null) {
      fail(-1, e.message);
    } else {
      // ToastUtils.getInstance().toastFail(e.message);
    }
  }
}

HeaderInterceptor

///    author : luzi
///    date   : 2021/7/11
///    desc   : 请求头拦截器
class HeaderInterceptor extends Interceptor {
  @override
  Future<void> onRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    Map<String, dynamic> headers = options.headers;
    headers['clientId'] = 1; //渠道(1.APP 2.Web)
    if (Platform.isAndroid) {
      headers['systemName'] = 'Android'; //系统名称
    } else if (Platform.isIOS) {
      headers['systemName'] = 'iOS'; //系统名称
    }

    var time = DateTime.now().millisecondsSinceEpoch;
    headers['ts'] = time; //时间戳
    String sign = getParamsStr(options, time);
    headers['sign'] = sign; //参数加密签名
    headers['language'] = Get.locale?.countryCode ?? 'MY'; //语言环境
    headers['Accept'] = 'application/json';
    options.headers = headers;
    handler.next(options);
  }

  getParamsStr(RequestOptions options, int time) {
    StringBuffer stringBuffer = new StringBuffer();
    String? paramsStr;
    var method = options.method;
    if (method == 'GET') {
      if (options.queryParameters.isNotEmpty) {
        String query = options.uri.query;
        var splitArray = query.split('&');
        var splayTreeMap = new SplayTreeMap();
        splitArray.forEach((split) {
          var splitChild = split.split('=');
          splayTreeMap[splitChild[0]] = Uri.encodeQueryComponent(splitChild[1]);
        });
        paramsStr = json.encode(splayTreeMap);
        if (paramsStr.isNotEmpty) {
          stringBuffer.write('$paramsStr&');
        } else {
          stringBuffer.write('{}&');
        }
      } else {
        stringBuffer.write('{}&');
      }
    } else if (method == 'POST') {
      var data = options.data;
      if (data is FormData) {
        if (data.fields.isNotEmpty) {
          String replace = data.fields
              .join(",")
              .replaceAll('MapEntry', '')
              .replaceAll('(', '')
              .replaceAll(')', '');
          paramsStr = replace;
          if (paramsStr.isNotEmpty) {
            stringBuffer.write('{$paramsStr}&');
          } else {
            stringBuffer.write('{}&');
          }
        } else {
          stringBuffer.write('{}&');
        }
      } else {
        paramsStr = jsonEncode(data);
        if (paramsStr.isNotEmpty) {
          stringBuffer.write('$paramsStr&');
        } else {
          stringBuffer.write('{}&');
        }
      }
    }
    // NativeUtils.sendNativeData(NativeUtils.NATIVE_LOG, paramsStr.toString());
    // print(paramsStr.toString());
    stringBuffer.write('ts=$time&');
    stringBuffer.write('tmpsign=${DioManager.getInstance().signKey}');
    String toString = stringBuffer.toString().replaceAll("\"", "");
    // NativeUtils.sendNativeData(NativeUtils.NATIVE_LOG, toString);
    // print(toString);
    // Get.log.printInfo(info: '拼接后:$toString');
    var content = new Utf8Encoder().convert(toString);
    var digest = md5.convert(content);
    String md5Encode = hex.encode(digest.bytes).toUpperCase();
    Get.log.printInfo(info: 'MD5:$md5Encode');
    return md5Encode;
  }
}

DioLogInterceptor

///    date   : 2021/7/11
///    desc   : 日志拦截器
class DioLogInterceptor extends Interceptor {
  /// Print request [Options]
  final bool request;

  /// Print request header [Options.headers]
  final bool requestHeader;

  /// Print request data [Options.data]
  final bool requestBody;

  /// Print [Response.data]
  final bool responseBody;

  /// Print [Response.headers]
  final bool responseHeader;

  /// Print error message
  final bool error;

  /// InitialTab count to logPrint json response
  static const int initialTab = 1;

  /// 1 tab length
  static const String tabStep = '    ';

  /// Print compact json response
  final bool compact;

  /// Width size per logPrint
  final int maxWidth;

  /// Log printer; defaults logPrint log to console.
  /// In flutter, you'd better use debugPrint.
  /// you can also write log in a file.
  void Function(Object object) logPrint;

  DioLogInterceptor({
    this.request = true,
    this.requestHeader = true,
    this.requestBody = true,
    this.responseHeader = false,
    this.responseBody = true,
    this.error = true,
    this.maxWidth = 90,
    this.compact = true,
    this.logPrint = print,
  });

  @override
  void onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    if (request) {
      _printRequestHeader(options);
    }
    if (requestHeader) {
      _printMapAsTable(options.queryParameters, header: 'Query Parameters');
      final requestHeaders = Map();
      requestHeaders.addAll(options.headers);
      requestHeaders['contentType'] = options.contentType?.toString();
      requestHeaders['responseType'] = options.responseType.toString();
      requestHeaders['followRedirects'] = options.followRedirects;
      requestHeaders['connectTimeout'] = options.connectTimeout;
      requestHeaders['receiveTimeout'] = options.receiveTimeout;
      _printMapAsTable(requestHeaders, header: 'Headers');
      _printMapAsTable(options.extra, header: 'Extras');
    }
    if (requestBody && options.method != 'GET') {
      final data = options.data;
      if (data != null) {
        if (data is Map) _printMapAsTable(options.data, header: 'Body');
        if (data is FormData) {
          final formDataMap = Map()
            ..addEntries(data.fields)
            ..addEntries(data.files);
          _printMapAsTable(formDataMap, header: 'Form data | ${data.boundary}');
        } else
          _printBlock(data.toString());
      }
    }
    handler.next(options);
  }

  @override
  void onError(
    DioError err,
    ErrorInterceptorHandler handler,
  ) async {
    if (error) {
      if (err.type == DioErrorType.response) {
        final uri = err.response?.requestOptions.uri;
        _printBoxed(
            header:
                'DioError ║ Status: ${err.response?.statusCode} ${err.response?.statusMessage}',
            text: uri.toString());
        if (err.response != null && err.response?.data != null) {
          logPrint('╔ ${err.type.toString()}');
          if (err.response != null) {
            _printResponse(err.response!);
          }
        }
        _printLine('╚');
        logPrint('');
      } else
        _printBoxed(header: 'DioError ║ ${err.type}', text: err.message);
    }
    handler.next(err);
  }

  @override
  void onResponse(
    Response response,
    ResponseInterceptorHandler handler,
  ) async {
    if (responseHeader) {
      final responseHeaders = Map<String, String>();
      response.headers
          .forEach((k, list) => responseHeaders[k] = list.toString());
      _printMapAsTable(responseHeaders, header: 'Headers');
    }

    if (responseBody) {
      _printResponseHeader(response);
      logPrint('╔ Body');
      logPrint('║');
      _printResponse(response);
      logPrint('║');
      _printLine('╚');
    }
    handler.next(response);
  }

  void _printBoxed({String? header, String? text}) {
    logPrint('');
    logPrint('╔╣ $header');
    logPrint('║  $text');
    _printLine('╚');
  }

  void _printResponse(Response response) {
    if (response.data != null) {
      if (response.data is Map)
        _printPrettyMap(response.data);
      else if (response.data is List) {
        logPrint('║${_indent()}[');
        _printList(response.data);
        logPrint('║${_indent()}[');
      } else
        _printBlock(response.data.toString());
    }
  }

  void _printResponseHeader(Response? response) {
    final uri = response?.requestOptions.uri;
    final method = response?.requestOptions.method;
    //添加以下代码,防止多接口请求时 response的header和body被分开打印
    String header =
        'Response ║ $method ║ Status: ${response?.statusCode} ${response?.statusMessage}';
    logPrint('╔╣ $header' + ('═' * 70));
    logPrint('║  ${uri.toString()}');
    logPrint('║  ');
  }

  void _printRequestHeader(RequestOptions? options) {
    final uri = options?.uri;
    final method = options?.method;
    _printBoxed(header: 'Request ║ $method ', text: uri.toString());
  }

  void _printLine([String pre = '', String suf = '╝']) =>
      logPrint('$pre${'═' * maxWidth}$suf');

  void _printKV(String key, Object? v) {
    final pre = '╟ $key: ';
    final msg = v.toString();

    if (pre.length + msg.length > maxWidth) {
      logPrint(pre);
      _printBlock(msg);
    } else
      logPrint('$pre$msg');
  }

  void _printBlock(String msg) {
    int lines = (msg.length / maxWidth).ceil();
    for (int i = 0; i < lines; ++i) {
      logPrint((i >= 0 ? '║ ' : '') +
          msg.substring(i * maxWidth,
              math.min<int>(i * maxWidth + maxWidth, msg.length)));
    }
  }

  String _indent([int tabCount = initialTab]) => tabStep * tabCount;

  void _printPrettyMap(Map data,
      {int tabs = initialTab, bool isListItem = false, bool isLast = false}) {
    final bool isRoot = tabs == initialTab;
    final initialIndent = _indent(tabs);
    tabs++;

    if (isRoot || isListItem) logPrint('║$initialIndent{');

    data.keys.toList().asMap().forEach((index, key) {
      final isLast = index == data.length - 1;
      var value = data[key];
//      key = '\"$key\"';
      if (value is String) value = '\"$value\"';
      if (value is Map) {
        if (compact && _canFlattenMap(value))
          logPrint('║${_indent(tabs)} $key: $value${!isLast ? ',' : ''}');
        else {
          logPrint('║${_indent(tabs)} $key: {');
          _printPrettyMap(value, tabs: tabs);
        }
      } else if (value is List) {
        if (compact && _canFlattenList(value))
          logPrint('║${_indent(tabs)} $key: ${value.toString()}');
        else {
          logPrint('║${_indent(tabs)} $key: [');
          _printList(value, tabs: tabs);
          logPrint('║${_indent(tabs)} ]${isLast ? '' : ','}');
        }
      } else {
        final msg = value.toString().replaceAll('\n', '');
        final indent = _indent(tabs);
        final linWidth = maxWidth - indent.length;
        if (msg.length + indent.length > linWidth) {
          int lines = (msg.length / linWidth).ceil();
          for (int i = 0; i < lines; ++i) {
            logPrint(
                '║${_indent(tabs)} ${msg.substring(i * linWidth, math.min<int>(i * linWidth + linWidth, msg.length))}');
          }
        } else
          logPrint('║${_indent(tabs)} $key: $msg${!isLast ? ',' : ''}');
      }
    });

    logPrint('║$initialIndent}${isListItem && !isLast ? ',' : ''}');
  }

  void _printList(List list, {int tabs = initialTab}) {
    list.asMap().forEach((i, e) {
      final isLast = i == list.length - 1;
      if (e is Map) {
        if (compact && _canFlattenMap(e))
          logPrint('║${_indent(tabs)}  $e${!isLast ? ',' : ''}');
        else
          _printPrettyMap(e, tabs: tabs + 1, isListItem: true, isLast: isLast);
      } else
        logPrint('║${_indent(tabs + 2)} $e${isLast ? '' : ','}');
    });
  }

  bool _canFlattenMap(Map map) {
    return map.values.where((val) => val is Map || val is List).isEmpty &&
        map.toString().length < maxWidth;
  }

  bool _canFlattenList(List list) {
    return (list.length < 10 && list.toString().length < maxWidth);
  }

  void _printMapAsTable(Map? map, {String? header}) {
    if (map == null || map.isEmpty) return;
    logPrint('╔ $header ');
    map.forEach((key, value) => _printKV(key, value));
    _printLine('╚');
  }
}

OperatingCenterEngine

class OperatingCenterEngine {

  static Future queryAlertInfo(Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    await DioManager.getInstance().get('warning-rules/getConfiguration',
        params: null, success: success, fail: fail);
  }


  static Future updateAlertInfo(
      String alertAmount, Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    SplayTreeMap<String, dynamic> map = new SplayTreeMap<String, dynamic>();
    map['alertAmount'] = alertAmount; 
    await DioManager.getInstance().postJson(
        'warning-rules/alertValueConfiguration',
        params: map,
        success: success,
        fail: fail);
  }


  static Future queryBindBankInfo(Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    await DioManager.getInstance().postJson('bank-card/cashDetail',
        params: null, success: success, fail: fail);
  }


  static Future addExample(
      SplayTreeMap<String, dynamic> map, Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    await DioManager.getInstance()
        .postJson('bank-card/save', params: map, success: success, fail: fail);
  }

  static Future updateExample(
      SplayTreeMap<String, dynamic> map, Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    await DioManager.getInstance().postJson('bank-card/update',
        params: map, success: success, fail: fail);
  }


  static Future getExampleList(Success<List<dynamic>> success,
      {Fail? fail}) async {
    SplayTreeMap<String, dynamic> map = new SplayTreeMap();
    map['dictCode'] = 'CASH_BANK';
    await DioManager.getInstance()
        .get('dict/listDictValue', params: map, success: success, fail: fail);
  }


  static Future getImageCodeNew( SplayTreeMap<String, dynamic> map,Success<Map<String, dynamic>> success,
      {Fail? fail}) async {
    // SplayTreeMap<String, dynamic> map = new SplayTreeMap();
    // map['ceshi'] = '123456999999';
    await DioManager.getInstance()
        .postJson('test', params: map, success: success, fail: fail);

  }
}

实际调用

   SplayTreeMap<String, dynamic> map = new SplayTreeMap();
          map['username'] ="你好" ;
          map['loongwind'] ="123456" ;
          OperatingCenterEngine.getImageCodeNew(map,(data) =>{
          print('你好============123456${data!['age']}'),
          });

上一篇下一篇

猜你喜欢

热点阅读