记录flutter项目之——对dio封装

3,230 阅读2分钟

记录学习flutter开发中的探索,借鉴了网上很多大佬的思路,如有雷同,那大概率是我抄的(手动狗头)。

此系列仅为记录个人学习中的思路。

文中所用环境及配置

flutter 2.2.3

dio 4.0.0

logger 1.1.0 #log输出

目录结构

image.png

大概封装内容

  • token校验

  • log输出

  • 异常处理

    ......

开始封装

http单例操作类:http_client.dart

这里仅写了get和post

class HttpClient {
  Dio _dio;
  //定义一个共用的取消令牌,可用于用户操作时token校验失败取消其他请求操作
  CancelToken cancelToken = CancelToken();
  static HttpClient _instance = HttpClient._internal();

  HttpClient._internal() {
    //请求头,依需求自己添加对应内容
    Map<String, dynamic> header = {};
    if (null == _dio) {
      _dio = Dio(
        BaseOptions(
          contentType: 'application/json',
          connectTimeout: 10000,
          receiveTimeout: 10000,
          sendTimeout: 10000,
          headers: header,
        ),
      );
      _dio.interceptors.add(MyHttpInterceptor());
    }
  }

  ///使用单例模式创建
  static HttpClient getInstance({String baseUrl}) {
    if (baseUrl == null) {
      return _instance._normal();
    } else {
      return _instance._otherDomain(baseUrl);
    }
  }

  ///用于指定域名
  ///因项目暂时没用到,所以先不做此方面的处理
  HttpClient _otherDomain(String baseUrl) {
    if (_dio != null) {
      _dio.options.baseUrl = baseUrl;
    }
    return this;
  }

  ///返回默认域名
  HttpClient _normal() {
    if (_dio != null) {
      if (_dio.options.baseUrl != NetWorkAddress.baseUrl) {
        _dio.options.baseUrl = NetWorkAddress.baseUrl;
      }
    }
    return this;
  }

  Future<BaseResponse> get({
    String url,
    Map<String, dynamic> params,
    Map<String, dynamic> data,
    CancelToken cancelToken,
    ProgressCallback onReceiveProgress,
  }) async {
    try {
      Response response = await _dio.get(
        url,
        queryParameters: params,
        cancelToken: cancelToken ?? this.cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return handleResponse(response, cancelToken: cancelToken ?? this.cancelToken);
    } on Exception catch (e) {
      return handleException(e, cancelToken: cancelToken ?? this.cancelToken);
    }
  }

  Future<BaseResponse> post({
    String url,
    Map<String, dynamic> params,
    Map<String, dynamic> data,
    CancelToken cancelToken,
    ProgressCallback onReceiveProgress,
  }) async {
    try {
      Response response = await _dio.post(
        url,
        queryParameters: params,
        cancelToken: cancelToken ?? this.cancelToken,
        onReceiveProgress: onReceiveProgress,
      );
      return handleResponse(response, cancelToken: cancelToken ?? this.cancelToken);
    } on Exception catch (e) {
      return handleException(e, cancelToken: cancelToken ?? this.cancelToken);
    }
  }
}

自定义拦截器: http_interceptor.dart

此处仅进行了log输出,未作其他处理

class MyHttpInterceptor extends InterceptorsWrapper {

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    super.onRequest(options, handler);
    logger.i("----------请求---------\nurl: ${options.uri.toString()}\n"
        "headers: ${options.headers}\nmethod: ${options.method}\nparams: ${options.queryParameters}\n"
        "data: ${options.data}");
  }
  @override
  void onResponse(Response response, ResponseInterceptorHandler handler) {
    super.onResponse(response, handler);
    //此处因为直接打印response的话,所输出的json串会无引号,所以添加一下转换
    var json = jsonEncode(response.data);
    logger.i("----------返回---------\nurl: ${response.requestOptions.uri}\n"
        "code: ${response.statusCode}\nmessage: ${response.statusMessage}\ndata: $json");
  }

  @override
  void onError(DioError err, ErrorInterceptorHandler handler) {
    super.onError(err, handler);
    logger.e("----------错误---------\ntype: ${err.type}\nmessage: ${err.message}");
  }
}

返回结果处理:http_response.dart

BaseResponse handleResponse(Response response, {CancelToken cancelToken,}) {
  // 返回值异常
  if (response.statusCode != 200)
    return handleException(
        HttpException(response.statusMessage, response.statusCode),
        cancelToken: cancelToken,
    );
  return BaseResponse(
    code: response.statusCode,
    message: response.statusMessage,
    data: response.data,
  );
}

///处理异常
BaseResponse handleException(Exception exception, {CancelToken cancelToken,}) {
  HttpException _parseException;
  if (exception is HttpException) _parseException = exception;
  else _parseException = parseException(exception);
  //在这里可进行异常处理
  logger.e("----------异常处理---------\n${_parseException.toString()}");
  return BaseResponse(code: _parseException.code, message: _parseException.message);
}

///解析异常
HttpException parseException(Exception exception) {
  if (exception is DioError) {
    switch (exception.type) {
      case DioErrorType.connectTimeout:
        return HttpException("连接超时,请重试");
      case DioErrorType.sendTimeout:
        return HttpException("请求超时,请稍后重试");
      case DioErrorType.receiveTimeout:
        return HttpException("请求失败,请稍后重试");
      case DioErrorType.cancel: //请求被取消
        return HttpException(exception.message);
      case DioErrorType.response:
        try {
          int code = exception.response?.statusCode;
          switch (code) {
            case 401:
              return HttpException("登录失效", code);
            case 500:
              return HttpException(exception.response?.statusMessage, 500);
            case 400:
            default:
              return HttpException(exception.response?.statusMessage, code);
          }
        } on Exception catch (_) {
          return HttpException(exception.response.statusMessage);
        }
        return HttpException(exception.response.statusMessage);
      default: //未知异常
        return HttpException(exception.message, exception.hashCode);
    }
  } else {
    return HttpException(exception.toString());
  }
}

返回的数据类型:response_model.dart

class BaseResponse<T>{
  int code;
  String message;
  T data;
  BaseResponse({this.code,this.message,this.data});

  @override
  String toString() {
    return "code: $code\nmessage: $message\ndata: $data";
  }
}

自定义的异常,方便后期学到新知识扩展:http_exception.dart

class HttpException implements Exception{
  final String _message;
  String get message => _message ?? this.runtimeType.toString();
  final int _code;
  int get code => _code ?? -1;

  HttpException([this._message, this._code]);

  String toString() {
    return "code: $code\nmessage: $message";
  }
}

使用

var response = HttpClient.getInstance().get(url: NetWorkAddress.userInfo,);

到此封装结束。

最后

在写下这篇时,仍然查阅了许多前辈写的dio封装文章,收获颇多,这篇文章属实是小巫见大巫,纯粹是个人学习的记录(因为经常看过就忘记。。。),有什么写得不对的地方,大佬们请见谅~