Flutter怎么搭建一套健壮可靠的网络框架

Flutter怎么搭建一套健壮可靠的网络框架

网络框架的搭建

所需依赖库

  dio: ^4.0.0 # 网络框架
  connectivity: ^3.0.6 # 网络框架相关
  crypto: ^3.0.1 #加密库

具体实现

NetBaseRequest类对外暴露的方法

abstract class NetBaseRequest{
   request(NetData data);
   download(NetData data,{Function(int,int)? progressCallback});
   upload(NetData data,{Function(int,int)? sendProgressCallback});
   cancelRequest({NetCancelToken? token});
}

对NetBaseRequest类方法的具体实现

class NetRequest extends NetBaseRequest {
  late Dio dio;
  late NetCancelToken _cancelToken;

  NetRequest() {
    dio = Dio();
    _cancelToken = NetCancelToken();
    dio.interceptors.add(NetCommonInterceptor());
    dio.interceptors.addAll(NetWorkManger().interceptors);
    if (NetWorkManger().isPrintLog) {
      dio.interceptors.add(LogInterceptor(
          requestBody: true,
          responseBody: true,
          logPrint: (value) {
            print(value);
          }));
      (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =  (HttpClient client) {
        client.badCertificateCallback = (X509Certificate cert, String host, int port) =>true;
        return client;
      };
    }
  }

  ///下载
  @override
  Future<NetData> download(NetData data,
      {Function(int, int)? progressCallback}) async {
    dio.options = _initOptions(data);
    Response response = await dio.download(data.url, data.downloadFilePath,
        cancelToken: data.cancelToken ?? _cancelToken,
        queryParameters: data.params,
        onReceiveProgress: progressCallback);
    return _responseData(data, response);
  }

  BaseOptions _initOptions(NetData data) {
    BaseOptions baseOptions = BaseOptions();
    baseOptions.contentType = data.contentType;
    baseOptions.connectTimeout = data.connectTimeOut;
    baseOptions.receiveTimeout = data.readTimeout;
    baseOptions.headers = data.header;
    baseOptions.responseType = ResponseType.json;
    _addDioProxy(data);
    return baseOptions;
  }

  @override
  Future<NetData> request(NetData data) async {
    dio.options = _initOptions(data);
    try {
      switch (data.requestType) {
        case RequestType.GET:
          return await _requestGet(data);
        case RequestType.POST:
          return await _requestPost(data);
      }
    } on DioError catch (e) {
      var response = e.response;
      if (response != null) {
        if (response.data != null) {
          data.resultStatus = ResultStatus.success;
          data.resultData = response.data;
          NetWorkManger().responseInterceptor?.responseInterceptor(data);
          return data;
        }
      }
      _requestError(data);
      return data;
    }
  }

  ///get网络请求
  _requestGet(NetData data) async {
    Response response;
    if (data.params == null) {
      response = await dio.get(data.url,
          cancelToken: data.cancelToken ?? _cancelToken);
    } else {
      response = await dio.get(data.url,
          queryParameters: data.params,
          cancelToken: data.cancelToken ?? _cancelToken);
    }
    return _responseData(data, response);
  }

  ///post网络请求
  _requestPost(NetData data) async {
    Response response;
    if (data.params == null) {
      response = await dio.post(data.url,
          cancelToken: data.cancelToken ?? _cancelToken);
    } else {
      response = await dio.post(data.url,
          data: data.params, cancelToken: data.cancelToken ?? _cancelToken);
    }
    return _responseData(data, response);
  }

  ///文件上传
  @override
  upload(NetData data, {Function(int, int)? sendProgressCallback}) async {
    dio.options = _initOptions(data);
    if (data.uploadMap.isNotEmpty) {
      data.resultStatus = ResultStatus.processing;
      Map<String, dynamic> fileMap = {};
      data.uploadMap.forEach((key, value) {
        fileMap[key] =
            MultipartFile.fromFile(value, filename: getFileName(value));
      });
      FormData formData = FormData.fromMap(fileMap);
      Response response = await dio.post(data.url,
          data: formData,
          queryParameters: data.params,
          onSendProgress: sendProgressCallback,
          cancelToken: data.cancelToken ?? _cancelToken);
      return _responseData(data, response);
    }
  }

  ///返回数据解析
  _responseData(NetData data, Response response) {
    try {
      if (response.statusCode == 200) {
        data.resultStatus = ResultStatus.success;
        data.resultData = response.data;
        // data.rootBean = NetResponseBean.fromJson(response.data);
      } else {
        _requestError(data);
      }
    } catch (e) {
      _requestError(data);
    }

    //拦截器处理
    NetWorkManger().responseInterceptor?.responseInterceptor(data);
    return data;
  }

  ///添加网络代理,用于抓包
  _addDioProxy(NetData data) {
    try {
      if (data.isSetProxy &&
          data.proxyPort.isNotEmpty &&
          data.proxyIp.isNotEmpty) {
        (dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
            (HttpClient client) {
          client.findProxy = (uri) {
            return "PROXY ${data.proxyIp}:${data.proxyPort}";
          };
          client.badCertificateCallback =
              (X509Certificate cert, String host, int port) => true;
          return null;
        };
      }
    } catch (e) {
      print(e);
    }
  }

  @override
  cancelRequest({NetCancelToken? token}) {
    CancelToken _token = token ?? _cancelToken;
    _token.cancel();
  }

  _requestError(NetData data) {
    data.resultStatus = ResultStatus.serviceError;
    NetResponseBean root = NetResponseBean();
    root.success = "false";
    root.code = "-10001";
    root.msg = "网络异常,请稍后重试!";
    data.rootBean = root;
  }

  Future<bool> isConnected() async {
    var connectivityResult = await (Connectivity().checkConnectivity());
    if (connectivityResult == ConnectivityResult.mobile) {
      // I am connected to a mobile network.
      return true;
    } else if (connectivityResult == ConnectivityResult.wifi) {
      // I am connected to a wifi network.
      return true;
    }
    return false;
  }

  String getFileName(String filePath) {
    if (filePath.isEmpty || !filePath.contains("/")) {
      return "";
    }
    return filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length);
  }
}

配置参数NetData

class NetData {
  RequestType requestType = RequestType.POST; //请求类型
  Map<String, dynamic>? params; //参数
  Map<String, dynamic> header = NetWorkManger().header; //请求头
  String url = ""; //请求地址
  String baseUrl = "";
  NetCancelToken? cancelToken;

  ///上传,key是上传的key ,value是文件地址
  Map<String, String> uploadMap = {};

  ///下载储存文件的地址
  String downloadFilePath = '';

  int connectTimeOut = NetWorkManger().connectTimeOut; //连接超时时间:默认30秒
  int readTimeout = NetWorkManger().readTimeout; //读取超时时间:默认30秒
  String contentType = NetWorkManger().contentType; //http
  String proxyIp = NetWorkManger().proxyIp; //代理ip
  String proxyPort = NetWorkManger().proxyPort; //代理端口
  bool isSetProxy = NetWorkManger().isSetProxy; //是否开启代理

  //以下为返回数据
  ResultStatus? resultStatus; //请求状态
  dynamic resultData; //返回数据
  RequestType resultType = RequestType.POST; //解析
  NetBaseBean rootBean = NetResponseBean(); //解析bean 默认是rootBean 可以设置

  bool isEncryption = false; //参数,返回值是否加解密
  bool isShowLoading = false; //是否显示加载loading弹窗

  bool isSuccess() {
    return rootBean.isSuccess();
  }
}

网络框架的使用

参数说明

url 接口地址
type 请求方式
param 请求参数
token 删除请求token,new NetCanceToken即可使用
isEncryption 是否加密
isShowLoading 是否显示加载弹窗
success 成功,返回参数仅只是data数据,不包含code和msg
error 失败,参数返回code和msg

req(String url,  
   {RequestType type = RequestType.POST,  
   Map<String, dynamic>? param,  
   NetCancelToken? token,  
   bool isEncryption = false,  
   bool isShowLoading = true,  
   Function? success,  
   Function? error}) {}

继承调用方式

填空法
用填空的方式设置请求参数
继承BaseRequest<T>实现 T为返回data实体对象的类型
initApiUrl() 设置->url
addParam(String key, dynamic value) 设置->param
addParams(Map<String, dynamic> map) 设置->params
initReqType() 设置->get or post
jsonToData() 设置-> 填jsonData解析成T类型的方法
剩下参数 isEncryption isShowLoading等 需要更改可以在继承类中直接重写

调用

     TestRequest req = TestRequest();
     req.addParam("key", "value");
     req.req((data){ 成功返回T->data }, (code, msg) {失败code msg });

例子参考

class LoginRequest extends BaseRequest<User> {
  @override
  String initApiUrl() {
    return "http://xxxxx";
  }

  @override
  RequestType initReqType() {
    return RequestType.GET;
  }

  @override
  User jsonToData(Map<String, dynamic> jsonData) {
    return User.fromJson(jsonData);
  }
}

post调用

NetUtils().req("", 
     param: {},
     success: (success){},
     error: (code,msg){}); 

get调用

NetUtils().req("", 
     type = RequestType.GET,
     param: {},
     success: (success){},
     error: (code,msg){});    

#### 数据返回获取更多的信息
NetUtils().requestCommon("", 
     RequestType.GET,
     param: {}).then((value){  
     //TODO value是NetData,rootBean中包含接口返回的信息code,msg data  
});

上传

参数说明

url上传地址
uploadMap 参数
token 删除请求token,new NetCanceToken即可使用
sendProgressCallback 上传进度
isShowloading 是否显示加载弹框
success 成功
fail 失败

调用

NetUtils().requestUploadFile(String url,   
   Map<String,String> uploadMap,  
   {NetCancelToken? token,  
   Function(int, int)? sendProgressCallback,  
   bool isShowloading = true,  
   ValueChanged? success,  
   ValueChanged? fail}) {}  

下载

参数说明

url上传地址
filePath 储存路劲 ��
param 参数
token 删除请求token,new NetCanceToken即可使用
progressCallback 下载进度
isShowloading 是否显示加载弹框
success 成功
fail 失败

调用

requestDownLoading(String url,  
   String filePath,  
   {Map<String, dynamic>? param,  
   NetCancelToken? token,  
   Function(int, int)? progressCallback,  
   bool isShowloading = true,  
   ValueChanged? success,  
   ValueChanged? fail}) {}

修改baseUrl调用 NetWorkManger().baseUrl

url地址拼接上域名后,框架就不在拼接域名,可以用于多域名请求,解析的数据时,判断url是否包含当前域名

根据url中域名的判断可进行多种解析

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。