背景

我们知道dio是一个非常强大的Dart Http请求库,支持非常多的功能,如果我们单单只是在外层包裹一层业务相关的封装,如果业务场景稍微复杂一点,这一层封装就显得臃肿和冗余了,当ios14.4.1更新了什么然我ios越狱们的网络层本身json解析也是初始化电脑时出现问题为业务层服务,业务层有了需求,网络层自然得有响应了,只是iOS响应的方式应该遵循低耦合、可用性、可维护性、可扩展性等原则。

http代理

我在做iOS原生开发的时候深受Casa大神网络层设计的影响,这初始化电脑里将服务层(service)和接口层(api)划分开,这样做的好处有:

  1. 在面对不同服务时可单独配置相关的http强求配置,通常我们的应用在开发的过程中都不会只和一个服务交互,所以在这种场景下是非常有必要的。
  2. 服务层和接口层职责拆分,让他们做自己该做的事情。

Flutter Dio的分层封装

实现

jsonobject务层

服务层的职责包括:baseUrl的配appear置、服务公共请求头的配置、服务公共请求参数的配置、请求结果的加工、请求错误的统一处理等,除此之外还有token验证、log输出等。这里只提供一种封装思路具体的实现可json格式以根据业务场景自行实现。ios模拟器 首先我们会创建一个基类,这里命名为Service,首先每一个服务都应该拥有一个Dio实例:

import 'package:dio/dio.dart';
class Service {
  final Dio dio = Dio();
}

添加serviceKey

为了更好管理service,这里引入一个service来作为唯一标识。

import 'package:dio/dio.dart';
class Service {
  final Dio dio = Dio();
}

添加配置baJSONseUrl

这里httpwatch为了方json格式怎么打开便外部设置添加了setget方法:

import 'package:dio/dio.dart';
class Service {
  final Dio dio = Dio();
  late var _baseUrl = "";
  set baseUrl(value) {
    if (_baseUrl == value) {
      return;
    }
    _baseUrl = value;
    dio.options.baseUrl = _baseUrl;
  }
  get baseUrl => _baseUrl;
  String serviceKey() {
    return "";
  }
}

添加公共请求头、公共参http://192.168.1.1登录

import 'package:dio/dio.dart';
class Service {
  final Dio dio = Dio();
  /*...省略其他设置...*/
  Map<String, dynamic>? serviceHeader() {
    return null;
  }
  Map<String, dynamic>? serviceQuery() {
    return null;
  }
  Map<String, dynamic>? serviceBody() {
    return null;
  }
}

添加公共结果处理、错误处理

在请求结果到达后可对Api结果进行统一处理

import 'package:dio/dio.dart';
class Service {
  final Dio dio = Dio();
  /*...省略其他设置...*/
 Map<String, dynamic> responseFactory(Map<String, dynamic> dataMap) {
     /*...可对请求结果进行加工...*/
    return dataMap;
  }
  String errorFactory(DioError error) {
    // 请求错误处理
    String errorMessage = error.message;
    /*...具体的错误处理...*/
    return errorMessage;
  }
}

Service的管理

这里是引入了ios是什么意思一个manager来管理多个Servicemanagjson数据er为一个单例,用于注册和管理Service,实现也很简单,就使用一个serviceMap来存放Service,在使用服务前调用方法registeredService()注册需要服务即可,如果需要批量注册或者注销等功能自行添加即可appreciate

import 'service.dart';
class ServiceManager {
  static final ServiceManager _instance = ServiceManager._internal();
  factory ServiceManager() {
    return _instance;
  }
  ServiceManager._internal() {
    init();
  }
  Map serviceMap = {};
  void init() {}
  void registeredService(Service service) {
    service.initDio();
    String key = service.serviceKey();
    serviceMap[key] = service;
  }
}

Api层

Api层的职责包括设置path、请求参数的组装、请求method配置等功能了。

定义一个自定义的method

enum RequestMethod { get, post, put, delete, patch, copy }

serviceKey的配置

设置serviceKey是为了http://192.168.1.1登录指定该Api属于哪一个服务的:

class BaseApi {
  String serviceKey() {
    return "";
  }
}

加上path和method配置ios模拟器

class BaseApi {
  String serviceKey() {
    return "";
  }
  String path() {
    return "";
  }
  RequestMethod method() {
    return RequestMethod.get;
  }
}

核心request方法

此处只实现了部分methodios是苹果还是安卓,如有需求自行实现即可:

class BaseApi {
  /*...省略其他部分...*/
  void request(
      {Map<String, dynamic>? query,
      Map<String, dynamic>? body,
      Map<String, dynamic>? header,
      required Function successCallBack,
      required Function errorCallBack}) async {
    //获取到对应的服务
    Service service;
    if (ServiceManager().serviceMap.containsKey(serviceKey())) {
      service = ServiceManager().serviceMap[serviceKey()];
    } else {
      throw Exception('服务尚未注册');
    }
    Dio dio = service.dio;
    Response? response;
    Map<String, dynamic>? queryParams = {};
    var globalQueryParams = service.serviceQuery();
    if (globalQueryParams != null) {
      queryParams.addAll(globalQueryParams);
    }
    if (query != null) {
      queryParams.addAll(query);
    }
    Map<String, dynamic>? headerParams = {};
    var globalHeaderParams = service.serviceHeader();
    if (globalHeaderParams != null) {
      headerParams.addAll(globalHeaderParams);
    }
    if (header != null) {
      headerParams.addAll(header);
    }
    Map<String, dynamic>? bodyParams = {};
    var globalBodyParams = service.serviceBody();
    if (globalBodyParams != null) {
      bodyParams.addAll(globalBodyParams);
    }
    if (body != null) {
      bodyParams.addAll(body);
    }
    String url = path();
    Options options = Options(headers: headerParams);
    try {
      switch (method()) {
        case RequestMethod.get:
          if (queryParams.isNotEmpty) {
            response = await dio.get(url,
                queryParameters: queryParams, options: options);
          } else {
            response = await dio.get(url, options: options);
          }
          break;
        case RequestMethod.post:
          if (body != null && body.isNotEmpty) {
            response = await dio.post(url, data: body, options: options);
          } else {
            response = await dio.post(url, options: options);
          }
          break;
        default:
      }
    } on DioError catch (error) {
      errorCallBack(service.errorFactory(error));
    }
    if (response != null && response.data != null) {
      String dataStr = json.encode(response.data);
      Map<String, dynamic> dataMap = json.decode(dataStr);
      dataMap = service.responseFactory(dataMap);
      successCallBack(dataMap);
    }
  }
}

使用

实现服务层

继承与Service完成相应的父类方法重写以及ServiceKey的定义:

const String customServiceKey = "CustomService";
class CustomService extends Service {
  @override
  String serviceKey() {
    return customServiceKey;
  }
  @override
  Map<String, dynamic>? serviceHeader() {
    Map<String, dynamic> header = <String, dynamic>{};
    header["token"] = "...";
    return header;
  }
  //初始化Dio
  @override
  void initDio() {
    dio.options.headers = {
      "Content-Type": 'application/json',
    };
    dio.options.baseUrl = "http://abc/m/1234";
    dio.options.connectTimeout = 15000;
    dio.options.receiveTimeout = 8000;
    dio.options.contentType = "application/json";
    dio.interceptors.add(LogInterceptor(requestBody: true, responseBody: true));
  }
}

注册

在网络请求http://www.baidu.com前需要完成服务的注册:

void main() {
  runApp(MyApp());
  //注册服务
  ServiceManager().registeredService(CustomService());
}

Api的实现

Api的实现也是继承于BaseApi,然后实现iOS相关的父类方法重写即可:

class CustomApi extends BaseApi {
  @override
  String path() {
    return "/abc/api1";
  }
  @override
  RequestMethod method() {
    return RequestMethod.post;
  }
  @override
  String serviceKey() {
    //返回服务中定义的key
    return customServiceKey;
  }
}

Api的调用

对上面的Api发起请求例子:

void requestApi() {
    CustomApi api = CustomApi();
    Map<String, dynamic> body = {"key": value};
    api.request(
        body: body,
        successCallBack: (data) {
            /* 请求结果处理 */
        },
        errorCallBack: (error) {
            /* 请求失败结果处理 */
       }
    );
}

demo