Flutter网络请求数据封装最佳实践

实在学不动了,现在主流的java jdk版本应该是11以上了,可我仍旧使用jdk8。做为从jdk 1.5也就是jdk5一直走过来的老javaer真的不想学了,拖欠的太多了,很多新特性都不太清楚。

springboot大礼包也逐渐放弃java8的支持,已经官宣springboot3,java 17 将成为未来主流版本。

实际上版本的升级对我这种独立开发者也还好,成本并不是很高,只是我不想动。我只追求代码能跑,运行稳定即可。

从2021年开始,我逐渐将我的手机客户端程序尽可能的采用flutter开发,跨平台开发对来我来说尤其的重要,特别是针对UI层面的。

你很难想象我的代码版本库到底有都少个分支,特别是安卓版本早期一个渠道一个分支,每个渠道都要对接本渠道的sdk。我不得不维护一个自己整合个渠道的sdk,从而面对不同的渠道,从而减少分支版本期减轻代码的维护成本。直到现在我基本放弃了国内的应用市场,更多的经历只维护googleplay的版本。

之所以采用flutter开发客户端项目,一方面其跨平台的能力之外,另外就是新的开发语言 Dart,你想想看安卓目前有java 和 Kotlin,iOS 有 Object-C, swift,代码维护起来有点烦杂,特别是我这种单兵作战的独立开发者而言。所以这也是我为什么会逐渐采用flutter开发的主要原因。

未来的日子里,我会逐步整理我在开发过程中所使用的代码片段。

base_req_params.dart

1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class BaseReqParams {

String method = "POST"; //default method

String getUrl(); //baseUrl+"/sdk/init",here is "/sdk/init" without host

Map<String, dynamic> getBody();//post json body

String getMethod(){
return method;
}

}

base_resp_params.dart

1
2
3
4
5
6

abstract class BaseRespHandler {
BaseRespHandler fromJson(Map<String, dynamic> json);
Map<String, dynamic>? toJson();
}

base_service.dar

主网络请求类,所有的网络请求都是从这里类发出,并完成回调。

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121

import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_demo_v1/base/base_header_params.dart';
import 'package:flutter_demo_v1/utils/flog.dart';
import 'base_req_params.dart';

// class Session {
// static Map<String, dynamic> headers = {};
// static RespSignParams signParams;
// }

abstract class BaseService<T>{

static const String domainName = "http://192.168.3.167:8880";
final String baseUrl = domainName;

final int success = 200;
Dio dio = Dio();

BaseService(BuildContext context, {bool isShowLoading = true}) {
if (isShowLoading) {
//loading = new Loading();
//loading.init(context);
}
// dio.interceptors.add(CookieManager(cookieJar));
dio.options.baseUrl = baseUrl;
}

Options getOptions() {
return Options(
headers: getHeaders(),
followRedirects: false,
responseType: ResponseType.json,
contentType: Headers.jsonContentType,
validateStatus: (status) {
return status < 500;
}
);
}


///http请求的头的封装,根据实际业务进行扩展
Map<String, dynamic> getHeaders() {
HeaderParams params = HeaderParams(3, "eyJ1aWQiOjMsInRzIjoxLjYzNzIyNjc4ODU0MTkyNjVFMTJ9.1f3d833c8782ab26d62aeb19abce67e0");
Map<String, dynamic> newHeaders = params.toData();
return newHeaders;
}

///post json
void postByJson({required BaseReqParams params, required Function(Map<String, dynamic> data) onSuccess, required Function(int code, String msg) onFailed}) async {
// if (loading != null) {
// loading.show();
// }
try {

dlog("请求: ${dio.options.baseUrl}${params.getUrl()}");
dlog("body: ${params.getBody()}");
dlog("请求头: ${getOptions().headers}");

var response = await dio.post(
params.getUrl(),
data:params.getBody(),
options: getOptions());

//http response statuscode=200 代表服务器正常响应
if (response.statusCode == 200) {
var printString = json.encode(response.data);
dlog("返回: $printString");

Map<String, dynamic> rest = json.decode(printString);

var code = rest['code'];
var msg = rest['msg'];

dlog('[code]: ${rest['code']}');
dlog('[msg]: ${rest['msg']}');
dlog('[data]: ${rest['data']}');

if(code == 200){
//服务器返回json 结构体code=200 代表业务逻辑正常
onSuccess(rest);
}else{
//服务器返回json 结构体code!=200 代表业务不正常,需要单独处理
onFailed(code,msg);
}
} else {
///MORE INFO
//http response statuscode=200 代表服务器响应不正常,如服务器宕机,网络波段等,比较常见的如 400:badreq,404:notfund,500:internal server err
//只要业务逻辑正常,通常都是200;返回statuscode是比较标准的做法,也是restful apis践行的做法,但是在我们的开发过程中除特殊情况,通常都是返回200.
//这里已经捕获,并通过`onFailed`回调,可能比较规范的做法需要增加一个 `onError`回调,单独处理 statuscode!=200 的异常情况
elog("response.statusCode!=200, is ${response.statusCode}, ${response.toString()}");
onFailed(response.statusCode, json.decode(response.toString())['msg']);
}
} on DioError catch(e) {
printError(e);
} finally {
// if (loading != null) {
// loading.dismiss();
// }
}
}

void printError(DioError e) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx and is also not 304.
if(e.response != null) {
elog(e.response.data);
elog(e.response.headers);
elog(e.response.request);
} else{
// Something happened in setting up or sending the request that triggered an Error
elog(e.request);
elog(e.message);
}
}
}



sdk_model.dart

请求消息数据封装,

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117

import 'package:flutter_demo_v1/base/base_req_params.dart';
import 'package:flutter_demo_v1/base/base_resp_params.dart';

/// req json data
// {"packageName":"包名","channelName":"渠道名","versionCode":1,"versionName":"版本名"}
class SDKInitReqData extends BaseReqParams{

String packageName;
String channelName;
int versionCode;
String versionName;

SDKInitReqData({required this.packageName,required this.channelName,required this.versionCode,required this.versionName});

@override
Map<String, dynamic> getBody() {
return {
"packageName":packageName,
"channelName":channelName,
"versionCode":versionCode,
"versionName":versionName,
};
}

@override
String getUrl() {
return "/test/reqHeadCheck";
}

}

/// resp json data
// {
// "code": 200,
// "msg": "ok",
// "data": {
// "versionCode": 1,
// "versionName": "版本名",
// "packageName": "包名",
// "channelName": "渠道名",
// "id": 5,
// "upd": {
// "status": 0,
// "versionCode": 0,
// "apkSize": 0
// },
// "cfg": {"ad":false,"login":true,"agree":true,"wx":"xxx"}
// }
// }
class SDKInitRespData extends BaseRespHandler{
late int versionCode;
late String versionName;
late String packageName;
late String channelName;

late Upd upd;
late Cfg cfg;

@override
SDKInitRespData fromJson(Map<String, dynamic> json) {
versionCode = json['versionCode'];
versionName = json['versionName'];
packageName = json['packageName'];
channelName = json['channelName'];

upd = Upd().fromJson(json['upd']);
cfg = Cfg().fromJson(json['cfg']);

return this;
}

@override
Map<String, dynamic>? toJson() {
return null;
}
}

class Upd extends BaseRespHandler{
late int status;
late int versionCode;
late int apkSize;

@override
Upd fromJson(Map<String, dynamic> json) {
status = json['status'];
versionCode = json['versionCode'];
apkSize = json['apkSize'];
return this;
}

@override
Map<String, dynamic>? toJson() {
return null;
}
}

class Cfg extends BaseRespHandler{
late bool ad;
late bool login;
late bool agree;
late String wx;

@override
Cfg fromJson(Map<String, dynamic> json) {
ad = json['ad'];
login = json['login'];
agree = json['agree'];
wx = json['wx'];
return this;
}

@override
Map<String, dynamic>? toJson() {
return null;
}
}
Fred范方青 wechat
项目合作请联系我私人微信: fredtv23
0%