Dio 泛型网络请求封装。带基类。带完整日志输出

Posted 安果移不动

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dio 泛型网络请求封装。带基类。带完整日志输出相关的知识,希望对你有一定的参考价值。

import 'dart:convert' as convert;
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:anguo/utils/app_info_utlis.dart';
import 'package:anguo/utils/my_flutter_toast.dart';
import 'package:anguo/utils/net_work_tools.dart';
import 'package:anguo/utils/passport_manager.dart';
import 'package:anguo/utils/time_utils.dart';
import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_ad/bean/base_bean.dart';
import 'package:flutter_ad/generated/json/base/json_convert_content.dart';
import 'package:flutter_ad/utils/key_utlis.dart';

class APIDio {
  // 工厂模式
  // late  static Dio dio
  static Dio? dio = null;

  static const int CONNECT_TIMEOUT = 10000;
  static const int RECEIVE_TIMEOUT = 10000;

  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 Dio createInstance() {
    //仅仅初始化一次。
    if (dio == null) {
      //设置请求参数 基础配置
      late int requestTime;
      late int revicerTime;
      int sRequestId = 0;
      dio = Dio();
      dio!.options = BaseOptions(
          connectTimeout: CONNECT_TIMEOUT,
          receiveTimeout: RECEIVE_TIMEOUT,
          headers: getHeader());
      //设置拦截器 打印日志等
      dio!.interceptors.add(InterceptorsWrapper(onRequest: (options, handler) {
        Map<String, dynamic> header = getHeader();
        requestTime = DateTime.now().millisecondsSinceEpoch;
        sRequestId++;
        return handler.next(options);
      }, onResponse: (response, handler) async {
        _printLog(response, sRequestId, requestTime);
        var resDataList = convert.jsonDecode(response.data);
        int code = resDataList['code'];
        if (code == 0 || code == 1) {
          return handler.next(response);
          //-200 token失效
        } else if (code == -200) {
          //当出现错误 把 msg 打出来
          ToastUtils.showToast("登录信息过期。请重新登录");
          PassportManager.logout();
          PassportManager.goLogin(KeyUtils.globalKey.currentState!.context)
              .then((value) => null);
        } else {
          ToastUtils.showToast(resDataList['msg']);
          return handler.reject(DioError(
              error: resDataList['msg'],
              requestOptions: response.requestOptions));
        }
      }, onError: (DioError e, handler) {
        return handler.next(e);
      }));
    }
    return dio!;
  }

// https://blog.csdn.net/zhayunbiao/article/details/109361229 网络请求优化
  static Future<void> _printLog(
      Response response, int sRequestId, int requestTime) async {
    int revicerTime = DateTime.now().millisecondsSinceEpoch;
    // print('***************** ${response.requestOptions.uri} *****************');
    // print('data: ${response.requestOptions.data}');
    // printMoreLineLog(response.toString());
    sRequestId++;
    String inputContent = "网络日志:\\n" +
        "--> sending request ${response.requestOptions.uri.toString()} \\n" +
        "method: ${response.requestOptions.method}\\n" +
        "sequence: ${sRequestId.toString()}\\n" +
        "requestTime: ${TimeUtils.formatTimebYtimeMillis(requestTime, "yyyy-MM-dd HH:mm:ss SSS")}\\n" +
        "params: ${response.requestOptions.queryParameters.toString()}\\n" +
        "data: ${response.requestOptions.data.toString()}\\n" +
        "header: \\n{\\n${response.requestOptions.headers.toString()}}\\n" +
        "<--received response for ${response.requestOptions.uri.toString()}\\n" +
        "sequence:  ${sRequestId.toString()}\\n" +
        "receivedTime: ${TimeUtils.formatTimebYtimeMillis(revicerTime, "yyyy-MM-dd HH:mm:ss SSS")}\\n" +
        "duration: ${(revicerTime - requestTime).toString()}\\n" +
        "response: ${response.toString()}\\n" +
        "header: \\n{\\n${response.headers.map.toString()}\\n";
    //直接运行
    if (kDebugMode || kProfileMode) {
      // LogUtil.d(inputContent);
      //测试环境下打印日志
      log(inputContent);
    }
  }

  static getHeader() {
    String? token = PassportManager.getUserInfo()?.accessToken;
    return {
      'Content-Type': 'application/x-www-form-urlencode',
      'Authorization': token != null && token.length > 0 ? 'Bearer $token' : '',
      'AppVersion': AppInfoUtils.getVersionName(),
      'channel': 'app_${Platform.isandroid ? "android" : "ios"}',
    };
  }

  static void _getResponse<T>({
    required String url,
    required String method,
    parameters,
    Function(T? t)? onSuccess,
    Function(String error)? onError,
  }) async {
    // try {
    Response response;
    Dio dio = createInstance();
    switch (method) {
      case GET:
        response = await dio.get(url, queryParameters: parameters);
        break;
      case PUT:
        response = await dio.put(url, queryParameters: parameters);
        break;
      case PATCH:
        response = await dio.patch(url, queryParameters: parameters);
        break;
      case DELETE:
        response = await dio.delete(url, queryParameters: parameters);
        break;
      default:
        response = await dio.post(url, data: parameters);
        break;
    }

    /// 拦截http层异常码
    if (response.statusCode == 200) {
      /// 这里做baseBena泛型解析,封装 并拦截后台code异常码,可拦截自定义处理
      Map<String, dynamic> jsonData = jsonDecode(response.data);

      var bean = BaseBean<T>();
      bean.msg = jsonData['msg'];
      bean.code = jsonData['code'];
      if (jsonData.containsKey("data")) {
        bean.data = JsonConvert.fromJsonAsT(jsonData['data']);
      }
      if (response.statusCode == 200 && onSuccess != null) {
        if (bean.code == 1) {
          onSuccess(bean.data);
        } else {
          if (onError != null) {
            //自定义网络请求错误
            onError(bean.msg);
          }
        }
      } else {
        if (onError != null) {
          onError(bean.msg);
        }
      }
    } else {
      throw Exception(
          'statusCode:${response.statusCode}+${response.statusMessage}');
    }
    // } catch (e) {
    //   print('请求出错:' + e.toString());
    //   if (onError != null) {
    //     onError(e.toString());
    //   }
    // }
  }

  static Future<dynamic> get<T>(
      {required String url,
      required parameters,
      Function(T? t)? onSuccess,
      Function(String error)? onError}) async {
    NetWorkUtils.connectTips();
    _getResponse<T>(
        url: url,
        method: GET,
        parameters: parameters,
        onSuccess: onSuccess,
        onError: onError);
  }

  static Future<dynamic> post<T>(
      {required String url,
      required parameters,
      Function(T? t)? onSuccess,
      Function(String error)? onError}) async {
    try {
      NetWorkUtils.connectTips();
      _getResponse<T>(
          url: url,
          method: POST,
          parameters: parameters,
          onSuccess: onSuccess,
          onError: onError);
    } on DioError catch (e) {
      handleErr(e);
    }
  }

  static void handleErr(DioError e) {
    print(
      "DioError:${e.requestOptions.uri} ${e.message}",
    );
    if (e.message == null || e.message.isEmpty) return;

    throw '$e';
  }
}
class BaseBean<T> {
  late String msg;
  late int code;
  T? data;
}

实用范例

  static Future homeAdList(int page,
      {String? search, String? part, int? uid}) async {
    Map<String, dynamic>? param = {};
    if (uid != null) {
      param['uid'] = uid;
    }
    if (search != null) {
      param['search'] = uid;
    }
    param['page'] = page;

    await APIDio.get<AdListEntity>(
        url: APIConstant.list_ad,
        parameters: param,
        onSuccess: (AdListEntity? data) {
          print("onSuccess---------");
          print(data.adList.toString());
          print(data.totalPage.toString());
          print(data.currentPage.toString());
          print("onSuccess---------");
        },
        onError: (msg) {
          print("onError---------${msg}");
          print(msg);
        });
  }

打印结果

I/flutter (18097): onSuccess---------
I/flutter (18097): [Instance of 'AdListAdList']
I/flutter (18097): 1
I/flutter (18097): 1
I/flutter (18097): onSuccess---------

以上是关于Dio 泛型网络请求封装。带基类。带完整日志输出的主要内容,如果未能解决你的问题,请参考以下文章

Flutter--网络请求dio封装网络请求框架

Flutter网络请求Dio库的使用及封装

flutter dio网络请求封装经过多次修改更新 呕心沥血而成的封装版本 返回future 加入token的版本

Flutter学习日记之Http&Dio网络请求的使用与封装

flutter dio 网络请求问题

Flutter学习-网络请求