前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Flutter-Dart基于 Dio 的 HTTP 请求工具类

Flutter-Dart基于 Dio 的 HTTP 请求工具类

作者头像
老猫-Leo
发布2023-12-11 20:51:42
3962
发布2023-12-11 20:51:42
举报
文章被收录于专栏:前端大全前端大全

Flutter 基于 Dio 封装的一个 HTTP 请求工具类(XHttp),使用单例方便全局请求管理与使用。 包括请求拦截、响应拦截、错误拦截、请求 Hooks、日志输出、取消请求、取消重复请求、设置白名单、权限管控、基础请求等等功能。

代码

话不多说,直接上代码,欢迎大佬指导。(此处工具类我全部写在一起哦,当然也可以自己手动分开。)

代码语言:javascript
复制
// ignore_for_file: unnecessary_this

import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';

/// 全局网络请求 dio 实例 单例 XHttp
class XHttp {
  static const String GET = "GET";
  static const String POST = "POST";
  static const String PUT = "PUT";
  static const String PATCH = "PATCH";
  static const String DELETE = "DELETE";

  static const CUSTOM_ERROR_CODE = 'DIO_CUSTOM_ERROR'; // 自定义错误代码
  static const REQUEST_TYPE_STR = 'REQUEST'; // 请求类型字符串
  static const RESPONSE_TYPE_STR = 'RESPONSE'; // 响应类型字符串
  static const ERROR_TYPE_STR = 'RESPONSE_ERROR'; // 错误类型字符串
  static const DEFAULT_LOAD_MSG = '请求中...'; // 默认请求提示文字

  static const CONNECT_TIMEOUT = 60000; // 连接超时时间
  static const RECEIVE_TIMEOUT = 60000; // 接收超时时间
  static const SEND_TIMEOUT = 60000; // 发送超时时间

  static const DIALOG_TYPE_OTHERS = 'OTHERS'; // 结果处理-其他类型
  static const DIALOG_TYPE_TOAST = 'TOAST'; // 结果处理-轻提示类型
  static const DIALOG_TYPE_ALERT = 'ALERT'; // 结果处理-弹窗类型
  static const DIALOG_TYPE_CUSTOM = 'CUSTOM'; // 结果处理-自定义处理

  static String loadMsg = DEFAULT_LOAD_MSG; // 请求提示文字

  static String errorShowTitle = '发生错误啦'; // 错误提示标题

  static String errorShowMsg; // 错误提示文字

  static CancelToken cancelToken = CancelToken(); // 取消网络请求 token,默认所有请求都可取消。

  static CancelToken whiteListCancelToken = CancelToken(); // 取消网络请求白名单 token,此 token 不会被取消。

  Map<String, CancelToken> _pendingRequests = {}; // 正在请求列表

  static Dio dio;

  String _getBaseUrl() => 'https://xxx.com';

  /// 通用全局单例,第一次使用时初始化。
  XHttp._internal() {
    if (null == dio) {
      dio = Dio(BaseOptions(
        baseUrl: _getBaseUrl(),
        // contentType: ,
        // responseType: ,
        headers: {'Content-Type': 'application/json'},
        connectTimeout: CONNECT_TIMEOUT,
        receiveTimeout: RECEIVE_TIMEOUT,
        sendTimeout: SEND_TIMEOUT,
        extra: {'cancelDuplicatedRequest': true}, // 是否取消重复请求
      ));
      _init();
    }
  }

  /// 获取单例本身
  static final XHttp _instance = XHttp._internal();

  /// 取消重复的请求
  void _removePendingRequest(String tokenKey) {
    if (_pendingRequests.containsKey(tokenKey)) {
      // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除。
      _pendingRequests[tokenKey]?.cancel(tokenKey);
      _pendingRequests.remove(tokenKey);
    }
  }

  /// 初始化 dio
  void _init() {
    // 添加拦截器
    dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (RequestOptions options, handler) async {
          if (kDebugMode) {
            print("请求之前");
          }
          if (dio.options.extra['cancelDuplicatedRequest'] == true && options.cancelToken == null) {
            String tokenKey = [
              options.method,
              options.baseUrl + options.path,
              jsonEncode(options.data ?? {}),
              jsonEncode(options.queryParameters ?? {})
            ].join('&');
            _removePendingRequest(tokenKey);
            options.cancelToken = CancelToken();
            options.extra['tokenKey'] = tokenKey;
            _pendingRequests[tokenKey] = options.cancelToken;
          }
          _handleRequest(options, handler);
          // 有 token 时,添加 token。放打印日志后面,避免泄露 token。
          // 也可以登录成功后掉用 XHttp.setToken() 方法设置 token,但是持久化的话还是要这样最好。
          String token = 'Bearer xxxxx';
          if (token != dio.options.headers['authorization']) {
            dio.options.headers['authorization'] = token;
            options.headers['authorization'] = token; // 不设置的话第一次的请求会有问题,上面的是全局设置尚未对本条请求生效。
          }
          return handler.next(options);
        },
        onResponse: (Response response, ResponseInterceptorHandler handler) {
          if (kDebugMode) {
            print("响应之前");
          }
          _handleResponse(response, handler);
          RequestOptions option = response.requestOptions;
          if (dio.options.extra['cancelDuplicatedRequest'] == true && option.cancelToken == null) {
            _removePendingRequest(option.extra['tokenKey']);
          }
          String code = (response?.data ?? {})['code'];
          String msg = (response?.data ?? {})['msg'] ?? response.statusMessage;
          // 静态数据 或者 根据后台实际返回结构解析,即 code == '0' 时,data 为有效数据。
          bool isSuccess = option.contentType != null && option.contentType.contains("text") || code == '0';
          response.data = Result(response.data, isSuccess, response.statusCode, msg, headers: response.headers);
          return handler.next(response);
        },
        onError: (DioError error, handler) {
          if (kDebugMode) {
            print("出错之前");
          }
          _handleError(error);
          if (!CancelToken.isCancel(error) && dio.options.extra['cancelDuplicatedRequest'] == true) {
            _pendingRequests.clear(); // 不可抗力错误则清空列表
          }
          // 发生错误同时也会返回一个 Result 结构,通过这个 Result 可以拿到响应状态等信息。
          if (error.response != null && error.response?.data != null) {
            error.response.data = Result(
                error.response.data, false, error.response?.statusCode, errorShowMsg ?? error.response?.statusMessage,
                headers: error.response?.headers);
          } else {
            throw Exception(errorShowMsg);
          }
          return handler.next(error);
        },
      ),
    );
    // print("初始化 Dio 完成\n请求超时限制:$CONNECT_TIMEOUT ms\n接收超时限制:$RECEIVE_TIMEOUT ms\n发送超时限制:$SEND_TIMEOUT ms\nDio-BaseUrl:${dio.options.baseUrl}\nDio-Headers:${dio.options.headers}");
  }

  /// 请求 request 之前统一处理
  void _handleRequest(RequestOptions options, handler) {
    Toast.hide();
    Toast.loading(loadMsg);
    Map logData = {
      'url': options.baseUrl + options.path,
      'method': options.method,
      'headers': options.headers,
      'data': options.data ?? options.queryParameters, // GET 请求参数可以在 url 中,也可以使用 queryParameters,所以需要增加此判断。
    };
    _dealRequestInfo(logData, REQUEST_TYPE_STR);
  }

  /// 响应 response 之前统一处理
  void _handleResponse(Response response, handler) {
    Map logData = {
      'url': response.requestOptions.uri,
      'method': response.requestOptions.method,
      'headers': response.headers,
      'data': response.data,
      'statusCode': response.statusCode,
      'statusMessage': response.statusMessage,
    };
    _dealRequestInfo(logData, RESPONSE_TYPE_STR);
    Toast.hide();
  }

  /// 错误 error 统一处理
  void _handleError(DioError error) {
    // 也可以在此处根据状态码并处理错误信息,例如退出登录等等。
    String errorTypeInfo = '其他错误!';
    switch (error.type) {
      case DioErrorType.connectTimeout:
        errorTypeInfo = '连接超时!';
        break;
      case DioErrorType.sendTimeout:
        errorTypeInfo = "请求超时!";
        break;
      case DioErrorType.receiveTimeout:
        errorTypeInfo = "响应超时!";
        break;
      case DioErrorType.response:
        errorTypeInfo = "服务异常!";
        break;
      case DioErrorType.cancel:
        errorTypeInfo = "请求取消!";
        break;
      case DioErrorType.other:
      default:
        break;
    }
    Map logData = {
      'url': error.requestOptions.baseUrl + error.requestOptions.path,
      'method': error.requestOptions.method,
      'headers': error.response?.headers,
      'data': error.response?.data,
      'statusCode': error.response?.statusCode,
      'statusMessage': error.response?.statusMessage,
      'errorType': error.type,
      'errorMessage': error.message,
      'errorTypeInfo': errorTypeInfo,
    };
    _dealRequestInfo(logData, ERROR_TYPE_STR);
    Toast.hide();
    errorShowMsg =
        "$errorShowTitle ${error.response?.statusCode ?? 'unknown'} $errorTypeInfo \n ${error.response?.statusMessage ?? ''} ${error.message ?? ''} \n ${error.response?.data ?? ''}";
  }

  /// 合并打印请求日志 REQUEST RESPONSE RESPONSE_ERROR
  String _dealRequestInfo(Map logData, String logType) {
    String logStr = "\n";
    logStr += "========================= $logType START =========================\n";
    logStr += "- URL: ${logData['url']} \n";
    logStr += "- METHOD: ${logData['method']} \n";
    // logStr += "- HEADER: \n { \n";
    // logStr += parseData(logData['headers']);
    // logStr += "\n } \n";
    if (logData['data'] != null) {
      logStr += "- ${logType}_BODY: \n";
      logStr += "!!!!!----------*!*##~##~##~##*!*##~##~##~##*!*----------!!!!! \n";
      logStr += "${parseData(logData['data'])} \n";
      logStr += "!!!!!----------*!*##~##~##~##*!*##~##~##~##*!*----------!!!!! \n";
    }
    if (logType.contains(RESPONSE_TYPE_STR)) {
      logStr += "- STATUS_CODE: ${logData['statusCode']} \n";
      logStr += "- STATUS_MSG: ${logData['statusMessage']} \n";
    }
    if (logType == ERROR_TYPE_STR) {
      logStr += "- ERROR_TYPE: ${logData['errorType']} \n";
      logStr += "- ERROR_MSG: ${logData['errorMessage']} \n";
      logStr += "- ERROR_TYPE_INFO: ${logData['errorTypeInfo']} \n";
    }
    logStr += "========================= $logType E N D =========================\n";
    logWrapped(logStr);
    return logStr;
  }

  /// 统一结果提示处理
  Future _showResultDialog(Response response, resultDialogConfig) async {
    if (response == null) {
      return;
    }
    resultDialogConfig = resultDialogConfig ?? {};
    String dialogType = resultDialogConfig['type'] ?? XHttp.DIALOG_TYPE_TOAST;
    if (dialogType == XHttp.DIALOG_TYPE_OTHERS) {
      return; // 其他类型 OTHERS 自定义处理
    }
    bool isSuccess = response?.data?.success ?? false;
    String msg = response?.data?.msg ?? '未知错误';
    if (dialogType == XHttp.DIALOG_TYPE_TOAST) {
      // resultDialogConfig 可以有 successMsg, errorMsg
      isSuccess
          ? Toast.show(resultDialogConfig['successMsg'] ?? msg, type: Toast.SUCCESS)
          : Toast.show(resultDialogConfig['errorMsg'] ?? msg, type: Toast.ERROR);
      return;
    }
    if (dialogType == XHttp.DIALOG_TYPE_ALERT) {
      // resultDialogConfig 可以有 title, content, closeable, showCancel, cancelText, confirmText, confirmCallback, cancelCallback, closeCallback ...
      // Utils.showDialog(...);
      return;
    }
    if (dialogType == XHttp.DIALOG_TYPE_CUSTOM) {
      // resultDialogConfig 可以有 onSuceess, onError
      if (isSuccess) {
        if (resultDialogConfig['onSuccess'] != null) {
          resultDialogConfig['onSuccess'](response.data);
        }
      } else {
        if (resultDialogConfig['onError'] != null) {
          resultDialogConfig['onError'](response.data);
        }
      }
    }
  }

  /// 处理异常
  void _catchOthersError(e) {
    String errMsg = "${errorShowMsg ?? e}$CUSTOM_ERROR_CODE".split(CUSTOM_ERROR_CODE)[0];
    int errMsgLength = errMsg.length;
    String errshowMsg = errMsgLength > 300 ? errMsg.substring(0, 150) : errMsg;
    if (e is DioError) {
      if (CancelToken.isCancel(e)) {
        Toast.show('Cancel Request Successful'); // 取消重复请求可能会多次弹窗
        return;
      }
      Toast.show(errshowMsg, type: Toast.WARNING);
      return;
    }
    Toast.show(errshowMsg + "\n......", type: Toast.ERROR);
  }

  /// 本可以直接 XHttp.xxx 调用(添加 static 关键字给之后的 get/post 等方法),但是考虑多台服务器的情况,建议 XHttp.getInstance().xxx 调用。
  static XHttp getInstance({String baseUrl, String msg}) {
    String targetBaseUrl = baseUrl ?? _instance._getBaseUrl();
    loadMsg = msg ?? DEFAULT_LOAD_MSG;
    if (dio.options.baseUrl != targetBaseUrl) {
      dio.options.baseUrl = targetBaseUrl;
    }
    return _instance;
  }

  /// 取消普通请求
  static XHttp cancelRequest() {
    Toast.hide();
    if (dio.options.extra['cancelDuplicatedRequest'] == true) {
      _instance._pendingRequests.forEach((tokenKey, cancelToken) {
        cancelToken.cancel('cancel request $tokenKey');
      });
    } else {
      cancelToken.cancel('cancel request');
      cancelToken = CancelToken(); // 坑!取消后必须重新创建 cancelToken 否则后面使用原来 cancelToken 的请求会无效
    }
    return _instance;
  }

  /// 取消所有白名单 cancelToken 的请求
  static XHttp cancelWhiteListRequest() {
    Toast.hide();
    whiteListCancelToken.cancel('cancel whiteList request');
    whiteListCancelToken = CancelToken();
    return _instance;
  }

  /// 获取 cancelToken
  static CancelToken getCancelToken() {
    return cancelToken;
  }

  /// 获取 whiteListCancelToken
  static CancelToken getWhiteListCancelToken() {
    return whiteListCancelToken;
  }

  /// 获取一个新的 cancelToken
  static CancelToken getNewCancelToken() {
    return CancelToken();
  }

  /// get 请求
  Future get(String url, [Map<String, dynamic> params, resultDialogConfig, bool isCancelWhiteList = false]) async {
    // 可转为使用 request 代替,简化代码。
    // 写中括号可以忽略参数名称,因为必须按顺序传参。
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      if (params != null) {
        response = await dio.get(url, queryParameters: params, cancelToken: requestToken);
        return response.data;
      } else {
        response = await dio.get(url, cancelToken: requestToken);
        return response.data;
      }
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  /// post 请求
  Future post(String url, [Map<String, dynamic> data, resultDialogConfig, bool isCancelWhiteList = false]) async {
    // 可转为使用 request 代替,简化代码。
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio.post(url, data: data, cancelToken: requestToken);
      return response.data;
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  /// put 请求
  Future put(String url, [Map<String, dynamic> data, resultDialogConfig, bool isCancelWhiteList = false]) async {
    // 可转为使用 request 代替,简化代码。
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio.put(url, data: data, cancelToken: requestToken);
      return response.data;
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  /// patch 请求
  Future patch(String url, [Map<String, dynamic> data, resultDialogConfig, bool isCancelWhiteList = false]) async {
    // 可转为使用 request 代替,简化代码。
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio.patch(url, data: data, cancelToken: requestToken);
      return response.data;
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  /// delete 请求
  Future delete(String url, [Map<String, dynamic> data, resultDialogConfig, bool isCancelWhiteList = false]) async {
    // 可转为使用 request 代替,简化代码。
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio.delete(url, data: data, cancelToken: requestToken);
      return response.data;
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  /// request
  static Future request(
    String url, {
    String method = XHttp.GET,
    Map<String, dynamic> queryParameters,
    Map<String, dynamic> data,
    bool isCancelWhiteList = false,
    resultDialogConfig,
    Options options,
    void Function(int, int) onSendProgress,
    void Function(int, int) onReceiveProgress,
    String msg,
    String baseUrl,
  }) async {
    XHttp.getInstance(baseUrl: baseUrl, msg: msg);
    Response response;

    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }

    try {
      response = await dio.request(
        url,
        options: options ?? Options(method: method, contentType: Headers.formUrlEncodedContentType),
        queryParameters: queryParameters,
        data: data,
        cancelToken: requestToken,
        onReceiveProgress: onReceiveProgress,
        onSendProgress: onSendProgress,
      );
      return response.data;
    } catch (e) {
      _instance._catchOthersError(e);
    } finally {
      _instance._showResultDialog(
        response,
        resultDialogConfig ?? {'type': XHttp.DIALOG_TYPE_OTHERS},
      ); // request 请求默认都需自己处理结果
    }
  }

  /// 下载文件
  Future downloadFile(urlPath, savePath, [resultDialogConfig, bool isCancelWhiteList = false]) async {
    Response response;
    var requestToken;
    if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
      if (isCancelWhiteList) {
        requestToken = whiteListCancelToken;
      } else {
        requestToken = cancelToken;
      }
    }
    try {
      response = await dio.download(urlPath, savePath, onReceiveProgress: (int count, int total) {
        // 进度
        print("$count $total");
      }, cancelToken: requestToken);
      return response.data;
    } catch (e) {
      _catchOthersError(e);
    } finally {
      _showResultDialog(response, resultDialogConfig);
    }
  }

  // /// post 表单请求 【Web】
  // Future postForm(String url, [Map<String, dynamic> params, resultDialogConfig, bool isCancelWhiteList = false]) async {
  //   Response response;
  //   var requestToken;
  //   if (dio.options.extra['cancelDuplicatedRequest'] != true || isCancelWhiteList) {
  //     if (isCancelWhiteList) {
  //       requestToken = whiteListCancelToken;
  //     } else {
  //       requestToken = cancelToken;
  //     }
  //   }
  //   try {
  //     response = await dio.post(url, queryParameters: params, cancelToken: requestToken);
  //     return response.data;
  //   } catch (e) {
  //     _catchOthersError(e);
  //   } finally {
  //     _showResultDialog(response, resultDialogConfig);
  //   }
  // }

  /// +++++++++++++++++++++++++ 小扩展 【待增加:retry、代理/proxy、根据状态码自动退出与重连等】 +++++++++++++++++++++++++

  /// 获取当前的 baseUrl
  static String getBaseUrl() {
    return dio.options.baseUrl;
  }

  /// 设置当前的 baseUrl
  static XHttp setBaseUrl(String baseUrl) {
    dio.options.baseUrl = baseUrl;
    return _instance;
  }

  /// 获取当前 headers
  static Map getHeaders() {
    return dio.options.headers;
  }

  /// 获取当前 headers 属性
  static dynamic getHeader(String key) {
    return dio.options.headers[key];
  }

  /// 设置当前 headers
  static XHttp setHeaders(Map headers) {
    dio.options.headers = headers;
    return _instance;
  }

  /// 设置当前 headers 属性
  static XHttp setHeader(String key, String value) {
    dio.options.headers[key] = value;
    return _instance;
  }

  /// 删除当前的请求头属性
  static XHttp removeHeader(String key) {
    dio.options.headers.remove(key);
    return _instance;
  }

  /// 删除当前的所有请求头属性
  static XHttp removeAllHeaders() {
    dio.options.headers.clear();
    return _instance;
  }

  /// 获取当前的所有超时时间
  static Map getRequestTimeout() {
    return {
      'connectTimeout': dio.options.connectTimeout,
      'receiveTimeout': dio.options.receiveTimeout,
      'sendTimeout': dio.options.sendTimeout
    };
  }

  /// 设置当前的所有超时时间
  static XHttp setRequestTimeout(int timeout) {
    dio.options.connectTimeout = timeout;
    dio.options.receiveTimeout = timeout;
    dio.options.sendTimeout = timeout;
    return _instance;
  }

  /// 设置当前的连接超时时间
  static XHttp setConnectTimeout(int timeout) {
    dio.options.connectTimeout = timeout;
    return _instance;
  }

  /// 设置当前的接收超时时间
  static XHttp setReceiveTimeout(int timeout) {
    dio.options.receiveTimeout = timeout;
    return _instance;
  }

  /// 设置当前的发送超时时间
  static XHttp setSendTimeout(int timeout) {
    dio.options.sendTimeout = timeout;
    return _instance;
  }

  /// 获取用户数据
  static Map<String, dynamic> getAuthUser() {
    String token = dio.options.headers['authorization'];
    if (null == token) {
      return null;
    }
    // 解析token
    return {'account': 'xxx', 'name': 'xxx', 'roles': 'xxx'};
  }

  /// 设置当前 token
  static XHttp setAuthToken([String token]) {
    if (null == token) {
      dio.options.headers.remove('authorization');
    } else {
      dio.options.headers['authorization'] = token;
    }
    return _instance;
  }

  /// 设置错误提示标题
  static XHttp setErrorTitle(String msg) {
    errorShowTitle = msg;
    return _instance;
  }

  /// 判断是否是取消异常
  static bool isCancel(e) {
    return CancelToken.isCancel(e);
  }

  // /// 设置当前的请求数据格式
  // static XHttp setContentType(String contentType) {
  //   dio.options.contentType = contentType;
  //   return _instance;
  // }

  // /// 设置当前的请求数据格式
  // static XHttp setContentTypeMultipartForm() {
  //   dio.options.contentType = "multipart/form-data";
  //   return _instance;
  // }

  // /// 设置当前的请求返回数据格式
  // static XHttp setDataType(ResponseType dataType) {
  //   dio.options.responseType = dataType;
  //   return _instance;
  // }

  // /// 设置当前的请求返回数据格式
  // static XHttp setDataTypeJson() {
  //   dio.options.responseType = ResponseType.json;
  //   return _instance;
  // }

  // ----- [cookie/charset/accept/encoder/decoder] 这些都可以通过设置 headers 实现 -----
}

/// ====================================================== 以下内容为工具方法 ======================================================

/// 解析数据
String parseData(data) {
  String responseStr = "";
  if (data is Map) {
    responseStr += data.mapToStructureString();
  } else if (data is FormData) {
    final formDataMap = Map()
      ..addEntries(data.fields)
      ..addEntries(data.files);
    responseStr += formDataMap.mapToStructureString();
  } else if (data is List) {
    responseStr += data.listToStructureString();
  } else {
    responseStr += data.toString();
  }
  return responseStr;
}

/// 分段 log,可以写到 log 中。
void logWrapped(String text) {
  final pattern = RegExp('.{1,800}'); // 800 is the size of each chunk
  pattern.allMatches(text).forEach((match) => print(match.group(0)));
}

/// Map 拓展,Map 转结构化字符串输出。
extension Map2StringEx on Map {
  String mapToStructureString({int indentation = 0, String space = "  "}) {
    if (this == null || this.isEmpty) {
      return "$this";
    }
    String result = "";
    String indentationContent = space * indentation;
    result += "{";
    this.forEach((key, value) {
      if (value is Map) {
        result += "\n$indentationContent" + "\"$key\": ${value.mapToStructureString(indentation: indentation + 1)},";
      } else if (value is List) {
        result += "\n$indentationContent" + "\"$key\": ${value.listToStructureString(indentation: indentation + 1)},";
      } else {
        result += "\n$indentationContent" + "\"$key\": ${value is String ? "\"$value\"," : "$value,"}";
      }
    });
    result = result.substring(0, result.length - 1); // 去掉最后一个逗号
    result += "\n$indentationContent}";
    return result;
  }
}

/// List 拓展,List 转结构化字符串输出。
extension List2StringEx on List {
  String listToStructureString({int indentation = 0, String space = "  "}) {
    if (this == null || this.isEmpty) {
      return "$this";
    }
    String result = "";
    String indentationContent = space * indentation;
    result += "[";
    for (var value in this) {
      if (value is Map) {
        result +=
            "\n$indentationContent" + space + "${value.mapToStructureString(indentation: indentation + 1)},"; // 加空格更好看
      } else if (value is List) {
        result += value.listToStructureString(indentation: indentation + 1);
      } else {
        result += "\n$indentationContent" + value is String ? "\"$value\"," : "$value,";
      }
    }
    result = result.substring(0, result.length - 1); // 去掉最后一个逗号
    result += "\n$indentationContent]";
    return result;
  }
}

/// 结果处理
class Result {
  var data;
  bool success;
  int code;
  String msg;
  var headers;
  Result(this.data, this.success, this.code, this.msg, {this.headers});
}

class Toast {
  Toast._() {
    // EasyLoading 已全局初始化构建
    // EasyLoading.instance.loadingStyle = EasyLoadingStyle.custom;
    // 此处可自定义风格
  }
  static final Toast _instance = Toast._();

  static const String SUCCESS = "SUCCESS";
  static const String ERROR = "ERROR";
  static const String WARNING = "WARNING";
  static const String INFO = "INFO";

  static loading(String msg) {
    EasyLoading.show(status: msg);
  }

  static progeress(double value, String msg) {
    EasyLoading.showProgress(value, status: msg);
  }

  static show(String msg, {String type}) {
    switch (type) {
      case Toast.SUCCESS:
        EasyLoading.showSuccess(msg);
        break;
      case Toast.ERROR:
        EasyLoading.showError(msg);
        break;
      case Toast.WARNING:
        EasyLoading.showInfo(msg);
        break;
      case Toast.INFO:
      default:
        EasyLoading.showToast(msg);
        break;
    }
  }

  static hide() {
    EasyLoading.dismiss();
  }
}

// /// 使用示例:若未设置多个 baseUrl,可省略 getInstance(),记得给 get、post 设置 static 关键字或者直接初始化多个 baseUrl 的实例。也可以参考 request 在 get、post 方法中设置 baseUrl。
//  XHttp.getInstance().post("/user/login", {
//     "username": username,
//     "password": password
//   }).then((res) {
//     // DO SOMETHING
//   }).catchError((err) {
//     // DO SOMETHING
//   });

Demo

  • Github Dart_XHttp
  • Gitee Dart_XHttp
本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-02-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代码
  • Demo
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com