前言
本文为规范网络请求的编码文件位置和规范调用的方法。
一、网络请求接口使用简版
这里只介绍接口使用。详细的接口设计,详见下文。
1、基础请求接口(post/get)
1.1、不需要缓存 AppNetworkRequestUtil
1 2 3 4 5
| AppNetworkRequestUtil.post
AppNetworkRequestUtil.get
|
1.2、需要缓存 AppNetworkCacheUtil(默认一级缓存)
1 2 3 4 5
| AppNetworkCacheUtil.post
AppNetworkCacheUtil.get
|
2、列表请求接口
1.2、需要缓存 AppNetworkListCacheUtil(post)
1
| AppNetworkListCacheUtil.post
|
底层会调用 postListWithCallback
①、不需要特殊的pageSize时候,请求参数里无需设置 pageSize=20 ,底层会自动为你自动补上。
②、自动提取参数中的 pageNum,当发现pageNum为第一页的时候,底层会自动为你做第一页的缓存,且其他页不会做缓存。
二、接口使用规范+示例
1、接口使用规范
接口请求,统一写在每个模块的Request下。
附:已在前文《 项目目录结构规范 见《架构模式-①概览》 》 里的【7、服务类Service】中规范的Service结构如下:
7、服务类service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| │ ├─ service │ │ ├─ global_config │ │ │ ├─ manager │ │ │ │ └─ global_config_service.dart │ │ │ ├─ request │ │ │ │ └─ global_config_request.dart │ │ │ └─ cache │ │ │ └─ global_config_cache.dart │ │ └─ user │ │ ├─ manager │ │ │ └─ user_service.dart │ │ ├─ request │ │ │ └─ user_info_request.dart │ │ └─ cache │ │ └─ user_info_cache.dart
|
services/:包含应用程序的服务类或者管理中心,例如用户信息中心、配置信息中心等。
——-manager: 管理中心
——-request: 管理中心会需要的请求功能
——-cache: 管理中心可能需要的存储功能
2、示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class UserRequest { static login_normal({ String mobile, String smsCode, void Function(UserModel userModel) completeBlock, }) { return AppNetworkRequestUtil.post( UrlPath.doLogin, params: { "mobile": mobile, "smsCode": smsCode, "grantType": "sms_code", }, ).then((ResponseModel responseModel) { if (responseModel.isSuccess != true) { completeBlock(null); return; }
User_manager_bean baseUserModel; if (responseModel.result != null) { baseUserModel = UserModel.fromJson(responseModel.result); } else { baseUserModel = null; } completeBlock(baseUserModel); }); } }
|
三、网络请求机制设计
本点只介绍机制,请求的属性介绍,详见下文。
1、重试机制设计
接口:requestWithRetry –> requestUrl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| Future<ResponseModel> requestWithRetry( String api, { RequestMethod requestMethod = RequestMethod.post, Map<String, dynamic>? customParams, int retryCount = 0, Duration retryDuration = const Duration(milliseconds: 1000), bool Function(ResponseModel responseModel)? retryStopConditionConfigBlock, Options? options, bool withLoading = false, bool? toastIfMayNeed,
ResponseModel? beforeResponseModel, }) async { return requestUrl( api, requestMethod: requestMethod, customParams: customParams, options: options, withLoading: withLoading, toastIfMayNeed: toastIfMayNeed, ).then((ResponseModel responseModel) { if (beforeResponseModel != null) { if (responseModel.isEqualToResponse(beforeResponseModel)) { responseModel.isSameToBefore = true; } }
bool allowRetryIfFailure = retryCount > 1; if (allowRetryIfFailure != true) { return responseModel; }
bool noneedRetry = responseModel.isSuccess; if (retryStopConditionConfigBlock != null) { noneedRetry = retryStopConditionConfigBlock(responseModel); } if (noneedRetry) { return responseModel; } else { retryCount--;
return Future.delayed(retryDuration).then((value) { return requestWithRetry( api, requestMethod: requestMethod, customParams: customParams, retryCount: retryCount, retryDuration: retryDuration, retryStopConditionConfigBlock: retryStopConditionConfigBlock, options: options, withLoading: withLoading, toastIfMayNeed: toastIfMayNeed, beforeResponseModel: responseModel, ); }); } }); }
|
2、缓存机制设计
2.1、在重试基础上+缓存
接口:cache_requestWithCallback –> requestWithRetry –> requestUrl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| void cache_requestWithCallback( String api, { RequestMethod requestMethod = RequestMethod.post, Map<String, dynamic>? customParams, bool? ifNoAuthorizationForceGiveUpRequest, int retryCount = 0, NetworkCacheLevel cacheLevel = NetworkCacheLevel.none, required void Function(ResponseModel responseModel) completeCallBack, ResponseModel? cacheResponseModel, }) async {
if (ifNoAuthorizationForceGiveUpRequest == true) { if (await existAuthorization() == false) { return; } }
ResponseModel responseModel = await requestWithRetry( api, requestMethod: requestMethod, customParams: customParams, retryCount: retryCount, options: CacheHelper.buildOptions(cacheLevel), beforeResponseModel: cacheResponseModel, );
if (responseModel.isCache != true) { if (responseModel.isSuccess) { completeCallBack(responseModel); } else { if (cacheLevel != NetworkCacheLevel.none) { Uri uri = getUri(api); String requestMethodString = requestMethod.toString().split('.').last; bool deleteSuccess = await deleteByPrimaryKeyAndSubKeyWithUri(uri, requestMethod: requestMethodString, data: customParams); if (deleteSuccess == false) { _log("Warning:此份网络数据结果本不该存储,但存了,现在必须删却又没删除成功的接口"); } } completeCallBack(responseModel); } } else { completeCallBack(responseModel);
late NetworkCacheLevel newCacheLevel; if (cacheLevel == NetworkCacheLevel.one) { newCacheLevel = NetworkCacheLevel.forceRefreshAndCacheOne; } else { _log( 'Error:$api判断出错啦,此结果不是缓存数据,却走到了isCache==true'); newCacheLevel = NetworkCacheLevel .none; }
cache_requestWithCallback( api, requestMethod: requestMethod, customParams: customParams, cacheLevel: newCacheLevel, completeCallBack: completeCallBack, cacheResponseModel: responseModel, ); } }
|
3、整合成app层的requestWithCallback
接口:requestWithCallback –> cache_requestWithCallback –> requestWithRetry –> requestUrl
①、加入接口模拟mock
②、加入网络判断
③、加入loading
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| void requestWithCallback( String api, { RequestMethod requestMethod = RequestMethod.post, Map<String, dynamic>? customParams, bool? ifNoAuthorizationForceGiveUpRequest, int retryCount = 0, AppNetworkCacheLevel cacheLevel = AppNetworkCacheLevel.none, withLoading = false, bool? showToastForNoNetwork, required void Function(ResponseModel responseModel) completeCallBack, }) async { AppMockManager.tryDealApi( api, isGet: requestMethod == RequestMethod.get ? true : false, );
if (withLoading == true) { LoadingUtil.show(); }
cache_requestWithCallback( api, requestMethod: requestMethod, customParams: customParams, ifNoAuthorizationForceGiveUpRequest: ifNoAuthorizationForceGiveUpRequest, retryCount: retryCount, cacheLevel: cacheLevel == AppNetworkCacheLevel.one ? NetworkCacheLevel.one : NetworkCacheLevel.none, completeCallBack: (ResponseModel responseModel) { if (withLoading == true && responseModel.isCache != true) { LoadingUtil.dismiss(); }
ResponseModel newResponseModel = checkResponseModelFunction( responseModel, toastIfMayNeed: showToastForNoNetwork, );
completeCallBack(newResponseModel); }, ); }
|
4、callback转为Future的机制
接口:post/get –> requestWithCallback –> cache_requestWithCallback –> requestWithRetry –> requestUrl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| class AppNetworkCacheUtil { String api; Map<String, dynamic>? params; bool? ifNoAuthorizationForceGiveUpRequest; int retryCount; bool withLoading; AppNetworkCacheLevel cacheLevel; bool? showToastForNoNetwork;
RequestMethod requestMethod = RequestMethod.post;
AppNetworkCacheUtil.get( this.api, { this.params, this.ifNoAuthorizationForceGiveUpRequest, this.retryCount = 0, this.withLoading = false, this.cacheLevel = AppNetworkCacheLevel.one, this.showToastForNoNetwork, }) { requestMethod = RequestMethod.get; }
AppNetworkCacheUtil.post( this.api, { this.params, this.ifNoAuthorizationForceGiveUpRequest, this.retryCount = 0, this.withLoading = false, this.cacheLevel = AppNetworkCacheLevel.one, this.showToastForNoNetwork, }) { requestMethod = RequestMethod.post; }
void then( void Function(ResponseModel responseModel) completeCallBack, ) async { AppNetworkManager().requestWithCallback( api, requestMethod: requestMethod, customParams: params, ifNoAuthorizationForceGiveUpRequest: ifNoAuthorizationForceGiveUpRequest, retryCount: retryCount, cacheLevel: cacheLevel, withLoading: withLoading, showToastForNoNetwork: showToastForNoNetwork, completeCallBack: completeCallBack, ); } }
|
四、列表接口的缓存设计
方法:postListWithCallback
①、不需要特殊的pageSize时候,请求参数里无需设置 pageSize=20 ,底层会自动为你自动补上。
②、自动提取参数中的 pageNum,当发现pageNum为第一页的时候,底层会自动为你做第一页的缓存,且其他页不会做缓存。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| extension Cache on AppNetworkManager { void postListWithCallback( String api, { required Map<String, dynamic> customParams, int retryCount = 0, AppListCacheLevel listCacheLevel = AppListCacheLevel.one, withLoading = false, bool? showToastForNoNetwork, required void Function(ResponseModel responseModel) completeCallBack, }) async { if (customParams['pageSize'] == null) { customParams.addAll({"pageSize": 20}); }
AppNetworkCacheLevel cacheLevel = AppNetworkCacheLevel.none; if (customParams['pageNum'] != null) { int pageNum = customParams['pageNum']; if (listCacheLevel == AppListCacheLevel.one && pageNum == 1) { cacheLevel = AppNetworkCacheLevel.one; } }
requestWithCallback( api, requestMethod: RequestMethod.post, customParams: customParams, retryCount: retryCount, cacheLevel: cacheLevel, withLoading: withLoading, showToastForNoNetwork: showToastForNoNetwork, completeCallBack: completeCallBack, ); } }
|
五、接口属性介绍
1、错误toast
1.1、默认null
按照默认的公共设置,公共设置里会指明每种code的toast显示方式。
举例:非0都要是toast就toast,不toast就不弹
详情点击:《网络设计.graffle 中的 【code的toast设计】》
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| [ { "code": [Unknow], "message": "非常抱歉!服务器开小差了~", }, { "code": [ErrorTryCatch], "message": "非常抱歉!系统请求发生错误了~", }, { "code": [NoNetwork], # -1 "message": "目前无可用网络", }, { "code": [ErrorTimeout], "message": "请求超时", }, { "code": [ErrorDioCancel], "message": "请求取消", }, { "code": [ErrorDioResponse], "message": "非常抱歉!服务器开小差了~", }, { "code": [500, 503], "message": "非常抱歉!服务器开小差了~", }, { "code": [401+暂未登录或token已经过期], "message": "登录失效,请重新登录", }, { "code": [401+后台的其他message], "message": "Token不能为空或Token过期,请重新登录", }, { "code": "ErrorTimeout", "message": "请求超时", }, ]
|
1.2、!null
有任何错误都弹或者不弹
前端觉得应该弹出toast的地方是否要弹出toast(如网络code为500的时候),必须可为空,不为空的时候无法实现修改
1、null时候,即不设置true或false。