网络库接口文档

[toc]

网络库接口文档

前言

本文为规范网络请求的编码文件位置和规范调用的方法。

一、网络请求接口使用简版

这里只介绍接口使用。详细的接口设计,详见下文。

1、基础请求接口(post/get)

1.1、不需要缓存 AppNetworkRequestUtil

1
2
3
4
5
// post 请求
AppNetworkRequestUtil.post

// get 请求
AppNetworkRequestUtil.get

1.2、需要缓存 AppNetworkCacheUtil(默认一级缓存)

1
2
3
4
5
// post 请求
AppNetworkCacheUtil.post

// get 请求
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
16
> │  ├─ 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, // 应该弹出toast的地方是否要弹出toast(如网络code为500的时候),必须可为空是,不为空的时候无法实现修改

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
/// 可进行缓存的请求(需要多次返回结果)
// ignore: non_constant_identifier_names
void cache_requestWithCallback(
String api, {
RequestMethod requestMethod = RequestMethod.post,
Map<String, dynamic>? customParams,
bool? ifNoAuthorizationForceGiveUpRequest, // 没有 Authorization 的时候是否强制放弃请求
int retryCount = 0,
NetworkCacheLevel cacheLevel = NetworkCacheLevel.none,
required void Function(ResponseModel responseModel) completeCallBack,
ResponseModel? cacheResponseModel,
}) async {
/*
bool shouldGiveUp = await super.shouldGiveUpRequest(api);
// 此时可能网络初始化还没完成(PS:初始化操作在base_requestUrl中 await _initCompleter.future;)
if (shouldGiveUp) {
LogApiUtil.logCancelApi(api);
return;
}
*/

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,
);

// 不是真正的网络请求返回的Response\Error结果(eg:比如是取缓存的结果时候)
// bool noRealRequest = cacheLevel == NetworkCacheLevel.one;
if (responseModel.isCache != true) {
// 1、当请求结果是后台实际请求返回的时候:
if (responseModel.isSuccess) {
// ①.如果实际的请求成功,则直接返回
completeCallBack(responseModel);
} else {
// ②.如果实际的请求失败,由于 statusCode 在200到300之间的请求结果都会被保存起来,但我们此系统里他们可能是错误的。
// 如500,就不要保存起来了,防止请求的时候发现有缓存数据,使得页面使用到了保存的数据
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 {
// 2、请求结果是之前缓存的数据返回的(即结果是真正的网络请求返回的Response\Error结果)的时候,
// ①先把缓存返回回去,
// ②再继续发起实际的请求,且新请求为后台实际请求并且其要会保存请求成功的数据
completeCallBack(responseModel);

late NetworkCacheLevel newCacheLevel;
if (cacheLevel == NetworkCacheLevel.one) {
newCacheLevel = NetworkCacheLevel.forceRefreshAndCacheOne;
} else {
_log(
'Error:$api判断出错啦,此结果不是缓存数据,却走到了isCache==true'); // TODO:无网络的情况下会发生此现象
newCacheLevel = NetworkCacheLevel
.none; //TODO:临时为了走下去,应该自始至终都不会走到这里,这里之后要 throw Exception
}

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, // 没有 Authorization 的时候是否强制放弃请求
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,
);

// ignore: todo
/* ///TODO:判断不准确,临时注释起来
if (cacheLevel != NetworkCacheLevel.one) {
// 不是取缓存的请求的时候,才需要取网络
if (NetworkStatusManager().connectionStatus == NetworkType.none) {
ResponseModel newResponseModel = checkResponseModelFunction(
ResponseModel.nonetworkResponseModel(),
showToastForNoNetwork: showToastForNoNetwork,
);

if (completeCallBack != null) {
completeCallBack(newResponseModel);
}
return;
}
}
*/

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; // 没有 Authorization 的时候是否强制放弃请求
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 {
/// 列表的请求(未设置会自动补上 pageNum pageSize 参数)
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
bool? toastIfMayNeed; //可空字段

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。