zl程序教程

您现在的位置是:首页 >  前端

当前栏目

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

封装日志网络输出泛型 请求 完整 基类
2023-09-27 14:27:38 时间
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) {
        requestTime = DateTime.now().millisecondsSinceEpoch;
        sRequestId++;
        handler.next(options);
        return;
      }, onResponse: (response, handler) async {
        _printLog(response, sRequestId, requestTime);
        var resDataList = convert.jsonDecode(response.data);
        int code = resDataList['code'];
        if (code == 0 || code == 1) {
          handler.next(response);
          return ;
          //-200 token失效
        } else if (code == -200) {
          //当出现错误 把 msg 打出来
          ToastUtils.showToast("登录信息过期。请重新登录");
          PassportManager.logout();
          PassportManager.goLogin(KeyUtils.globalKey.currentState!.context)
              .then((value) => null);
        } else {
          //-1是返回错误
          // // ToastUtils.showToast(resDataList['msg']);
          //主动抛出异常
          // return handler.reject(DioError(
          //     error: resDataList['msg'],
          //     requestOptions: response.requestOptions));
          handler.next(response);
          return;
        }
      }, 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;
    var hearder = {
      'Content-Type': 'application/x-www-form-urlencode',
      'Authorization': token != null && token.length > 0 ? 'Bearer $token' : '',
      'AppVersion': AppInfoUtils.getVersionName(),
      'channel': 'app_${Platform.isAndroid ? "android" : "ios"}',
    };
    return hearder;
  }

  static Future _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<T>(jsonData['data']);
      }
      if (response.statusCode == 200 && onSuccess != null) {
        if (bean.code == 1 && onSuccess != null) {
          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();
    await _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 {
    NetWorkUtils.connectTips();
    await _getResponse<T>(
        url: url,
        method: POST,
        parameters: parameters,
        onSuccess: onSuccess,
        onError: onError);
  }

  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<AdListEntity>(int page,
      {String? search,
      String? part,
      int? uid,
      Function(AdListEntity? t)? onSuccess,
      Function(String error)? onError}) async {
    Map<String, dynamic>? param = {};
    if (uid != null) {
      param['uid'] = uid;
    }
    if (search != null) {
      param['search'] = uid;
    }
    param['page'] = page;

    return APIDio.get<AdListEntity>(
        url: APIConstant.list_ad,
        parameters: param,
        onSuccess: onSuccess,
        onError: onError);
  }

打印结果

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