背景
我们知道dio
是一个非常强大的Dart
Http
请求库,支持非常多的功能,如果我们单单只是在外层包裹一层业务相关的封装,如果业务场景稍微复杂一点,这一层封装就显得臃肿和冗余了,当ios14.4.1更新了什么然我ios越狱们的网络层本身json解析也是初始化电脑时出现问题为业务层服务,业务层有了需求,网络层自然得有响应了,只是iOS响应的方式应该遵循低耦合、可用性、可维护性、可扩展性等原则。
设http代理计
我在做iOS原生开发的时候深受Casa大神网络层设计的影响,这初始化电脑里将服务层(service
)和接口层(api
)划分开,这样做的好处有:
- 在面对不同服务时可单独配置相关的
http
强求配置,通常我们的应用在开发的过程中都不会只和一个服务交互,所以在这种场景下是非常有必要的。 - 服务层和接口层职责拆分,让他们做自己该做的事情。
实现
服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格式怎么打开便外部设置添加了set
和get
方法:
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
来管理多个Service
,managjson数据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