classHttpHelper{staticDio? mDio;staticBaseOptions? options;staticHttpHelper? httpHelper;CancelToken cancelToken =CancelToken();staticconstString GET ='get';staticconstString POST ='post';staticconstString PUT ='put';staticconstString PATCH ='patch';staticconstString DELETE ='delete';staticHttpHelper?get instance =>getInstance();staticDio?get dio =>getDio();staticHttpHelper?getInstance(){
httpHelper ??=HttpHelper();return httpHelper;}staticDio?getDio(){final token =GetStorage().read('token');finalMap<String,dynamic> headerMap ={};if(token !=null){
headerMap.putIfAbsent("Authorization",()=>"Bearer $token");}
options =BaseOptions(//请求基地址,可以包含子路径
baseUrl:Api.BASE_URL,//连接服务器超时时间,单位是毫秒.
connectTimeout:constDuration(seconds:10),//2.x中为接收数据的最长时限
receiveTimeout:constDuration(seconds:5),//Http请求头.
headers: headerMap,// 请求的Content-Type,默认值是"application/json; charset=utf-8".// /// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,// /// 可以设置此选项为 `Headers.formUrlEncodedContentType`, 这样[Dio]// /// 就会自动编码请求体.
contentType:Headers.jsonContentType,/// [responseType] 表示期望以那种格式(方式)接受响应数据。/// 目前 [ResponseType] 接受三种类型 `JSON`, `STREAM`, `PLAIN`.////// 默认值是 `JSON`, 当响应头中content-type为"application/json"时,dio 会自动将响应内容转化为json对象。/// 如果想以二进制方式接受响应数据,如下载一个二进制文件,那么可以使用 `STREAM`.////// 如果想以文本(字符串)格式接收响应数据,请使用 `PLAIN`.
responseType:ResponseType.json,);
mDio =Dio(options);
mDio?.interceptors.add(interceptorsWrapper());
mDio?.httpClientAdapter =IOHttpClientAdapter(
createHttpClient:(){final client =HttpClient();// Config the client.
client.findProxy =(uri){// Forward all request to proxy "localhost:8888".// Be aware, the proxy should went through you running device,// not the host platform.return'PROXY 192.168.0.191:8089';};// You can also create a new HttpClient for Dio instead of returning,// but a client must being returned here.return client;},);return mDio;}staticInterceptorsWrapperinterceptorsWrapper(){returnInterceptorsWrapper(onRequest:(options, handler){// Do something before request is sentreturn handler.next(options);//continue// 如果你想完成请求并返回一些自定义数据,你可以resolve一个Response对象 `handler.resolve(response)`。// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.//// 如果你想终止请求并触发一个错误,你可以返回一个`DioError`对象,如`handler.reject(error)`,// 这样请求将被中止并触发异常,上层catchError会被调用。}, onResponse:(response, handler){// Do something with response datareturn handler.next(response);// continue// 如果你想终止请求并触发一个错误,你可以 reject 一个`DioError`对象,如`handler.reject(error)`,// 这样请求将被中止并触发异常,上层catchError会被调用。}, onError:(DioError e, handler){// Do something with response errorif(e.response !=null){if(e.response?.statusCode ==401){ToastMsg.show("当前登录已过期,请重新登录!");Future.delayed(constDuration(milliseconds:1000),(){Get.offAllNamed(AppRoutes.LOGIN);});}elseif(e.response?.statusCode ==403){ToastMsg.show("暂无权限访问,请联系管理员!");}else{ToastMsg.show("系统内部异常!");}}return handler.next(e);//continue// 如果你想完成请求并返回一些自定义数据,可以resolve 一个`Response`,如`handler.resolve(response)`。// 这样请求将会被终止,上层then会被调用,then中返回的数据将是你的自定义response.});}///Get请求Future<BaseRes<T>> getHttp<T>(String url, parameters,{loading =true})async{returnawait getResponse<T>(url, method: GET, parameters: parameters,loading:loading);}Future<BaseRes<T>> postHttp<T>(String url, parameters,{loading =true})async{///定义请求参数
parameters = parameters ??<String,dynamic>{};returnawait getResponse<T>(url, method: POST, parameters: parameters,loading:loading);}Future<BaseRes<T>> putHttp<T>(String url, parameters,{loading =true})async{///定义请求参数
parameters = parameters ??<String,dynamic>{};returnawait getResponse<T>(url, method: PUT, parameters: parameters,loading:loading);}Future<BaseRes<T>> deleteHttp<T>(String url, parameters,{loading =true})async{///定义请求参数
parameters = parameters ??<String,dynamic>{};returnawait getResponse<T>(url, method: DELETE, parameters: parameters,loading:loading);}/*
* 下载文件
*/downloadFile(urlPath, savePath, onReceiveProgress)async{Response? response;try{
response =await dio?.download(urlPath, savePath,
onReceiveProgress: onReceiveProgress);}onDioErrorcatch(e){formatError(e);}return response?.data;}Future<BaseRes<T>> getResponse<T>(String url,{
required String method,
parameters,
loading,})async{//这里指定response自动转成map,不指定的话有可能是String类型Response<Map<String,dynamic>>? response;if(loading){ToastMsg.showLoading();}switch(method){case GET:
response =await dio?.get(url,
queryParameters: parameters ??<String,dynamic>{});break;case PUT:
response =await dio?.put(url,
queryParameters: parameters ??<String,dynamic>{});break;case DELETE:
response =await dio?.delete(url,
queryParameters: parameters ??<String,dynamic>{});break;default:
response =await dio?.post(url, data: parameters ??<String,dynamic>{});break;}if(loading){ToastMsg.cancelLoading();}//200代表网络请求成功if(response?.statusCode ==200){/// 将后台的data字段转成自己想要的数据/数据集,code根据后端实际返回进行判断访问结果BaseRes<T> bean =BaseRes.fromJson(response?.data);return bean;}elseif(response?.statusCode ==401){ToastMsg.show("当前登录已过期,请重新登录!");Future.delayed(constDuration(milliseconds:1000),(){Get.offAllNamed(AppRoutes.LOGIN);});}elseif(response?.statusCode ==403){ToastMsg.show("暂无权限访问,请联系管理员!");}else{ToastMsg.show("系统内部异常!");}throwException('${response?.statusCode}+${response?.statusMessage}');}voidformatError(DioError e){print(e.message);}/*
* 取消请求
* 同一个cancel token 可以用于多个请求,当一个cancel token取消时,所有使用该cancel token的请求都会被取消。
*/voidcancelRequests(CancelToken token){
token.cancel("cancelled");}}
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
三、封装统一返回类
@JsonSerializable()classBaseRes<T>{BaseRes(this.msg,this.code,this.data);
late String msg;
late int code;
late T data;BaseRes.fromJson(Map<String,dynamic>? json){if(json?['data']!=null&& json?['data']!='null'){
data =JsonConvert.fromJsonAsT<T>(json?['data'])asT;}
msg = json?['msg'];
code = json?['code'];}Map<String,dynamic>toJson(){finalMap<String,dynamic> data =<String,dynamic>{};if(this.data !=null){
data['data']=this.data;}
data['code']=this.code;
data['msg']=this.msg;return data;}}
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
四、使用
// Entity类使用的是JsonToDartBeanAction生成BaseRes<UserInfoEntity>? res =awaitHttpHelper.instance?.getHttp(Api.GET_USER_INGO,null,loading:false);if(res?.code ==200&& res?.data !=null){
state.userInfo = res!.data.obs;}