1,http一個可組合的,基於Future的庫,用於發出HTTP請求。包含一組高級功能和類,可輕鬆使用HTTP資源。它與平臺無關,能夠在命令行和瀏覽器上使用。html
2,Dart的功能強大的Http客戶端,支持攔截器,全局配置,FormData,請求取消,文件下載,超時等。json
HttpClient
http
dio
本文主要介紹後面兩種網絡請求方式的封裝與使用,dart的原生網絡請求HttpClient可參考文檔經過HttpClient發起HTTP請求瀏覽器
第一步:添加依賴服務器
打開 pubspec.yaml文件,在
網絡dependencies
下添加以下包:
1 http: ^0.12.0+2 2 dio: ^3.0.4
保存後,通常會自動下載包;若是沒有自動下載可在項目根目錄下運行以下命令,進行下載:app
1 flutter packages get
第二步:引入包並建立網絡請求類async
1 import 'package:http/http.dart' as http;
1 class NetUtils { 2 3 ... 4 5 }
第三步:get方式請求post
1 // get請求的封裝,傳入的兩個參數分別是請求URL和請求參數,請求參數以map的形式傳入,會在方法體中自動拼接到URL後面 2 static Future<String> get(String url, {Map<String, String> params}) async { 3 if (params != null && params.isNotEmpty) { 4 // 若是參數不爲空,則將參數拼接到URL後面 5 StringBuffer sb = StringBuffer("?"); 6 params.forEach((key, value) { 7 sb.write("$key" + "=" + "$value" + "&"); 8 }); 9 String paramStr = sb.toString(); 10 paramStr = paramStr.substring(0, paramStr.length - 1); 11 url += paramStr; 12 } 13 http.Response res = await http.get(url, headers: getCommonHeader()); 14 return res.body; 15 }
第四步:POST方式請求this
1 // post請求 2 static Future<String> post(String url, {Map<String, String> params}) async { 3 http.Response res = await http.post(url, body: params, headers: getCommonHeader()); 4 print(res.statusCode); 5 return res.body; 6 }
其餘請求方式與post方式相似,這兒就不一一列舉其餘請求方式了。url
第五步:統一傳參處理
1 static Map<String, String> getCommonHeader() { 2 Map<String, String> header = Map(); 3 header['yingqi'] = "jackson影琪"; 4 return header; 5 }
第六步:完整代碼
1 import 'dart:async'; 2 import 'package:http/http.dart' as http; 3 4 class NetUtils { 5 // get請求的封裝,傳入的兩個參數分別是請求URL和請求參數,請求參數以map的形式傳入,會在方法體中自動拼接到URL後面 6 static Future<String> get(String url, {Map<String, String> params}) async { 7 if (params != null && params.isNotEmpty) { 8 // 若是參數不爲空,則將參數拼接到URL後面 9 StringBuffer sb = StringBuffer("?"); 10 params.forEach((key, value) { 11 sb.write("$key" + "=" + "$value" + "&"); 12 }); 13 String paramStr = sb.toString(); 14 paramStr = paramStr.substring(0, paramStr.length - 1); 15 url += paramStr; 16 } 17 http.Response res = await http.get(url, headers: getCommonHeader()); 18 return res.body; 19 } 20 21 // post請求 22 static Future<String> post(String url, {Map<String, String> params}) async { 23 http.Response res = await http.post(url, body: params, headers: getCommonHeader()); 24 print(res.statusCode); 25 return res.body; 26 } 27 28 // put請求 29 static Future<String> put(String url, {Map<String, String> params}) async { 30 http.Response res = await http.put(url, body: params, headers: getCommonHeader()); 31 return res.body; 32 } 33 34 static Map<String, String> getCommonHeader() { 35 Map<String, String> header = Map(); 36 header['yingqi'] = "1"; 37 return header; 38 } 39 40 }
第二步:引入包並建立網絡請求類
1 import 'dart:async'; 2 import 'package:dio/dio.dart'; 3 4 class DioNetUtils { 5 6 ... 7 8 }
第三步:初始化Dio
1 static final DioNetUtils _singleton = DioNetUtils._init(); 2 static Dio _dio; 3 4 DioNetUtils._init() { 5 BaseOptions options = new BaseOptions( 6 baseUrl: "http://192.168.1.19:8880", 7 connectTimeout: 1000 * 1, 8 receiveTimeout: 1000 * 2, 9 //Http請求頭. 10 headers: {//可統一配置傳參 11 //do something 12 "version": "1.0.0" 13 }, 14 //請求的Content-Type,默認值是"application/json; charset=utf-8". 也能夠用"application/x-www-form-urlencoded" 15 // contentType: "application/json; charset=utf-8", 16 //表示指望以那種格式(方式)接受響應數據。接受4種類型 `json`, `stream`, `plain`, `bytes`. 默認值是 `json`, 17 responseType: ResponseType.json, 18 ); 19 _dio = Dio(options); 20 21 }
第四步:添加攔截器
1 //添加攔截器 2 _dio.interceptors 3 .add(InterceptorsWrapper(onRequest: (RequestOptions options) { 4 print("請求以前處理"); 5 return options; //continue 6 }, onResponse: (Response response) { 7 print("響應以前處理"); 8 print(options); 9 return response; // continue 10 }, onError: (DioError e) { 11 print("錯誤以前提示"); 12 Response errorInfo = _dealErrorInfo(e); 13 return errorInfo; //continue 14 }));
第五步:統一處理錯誤信息
1 _dealErrorInfo(error) { 2 print(error.type); 3 // 請求錯誤處理 4 Response errorResponse; 5 if (error.response != null) { 6 errorResponse = error.response; 7 } else { 8 errorResponse = new Response(statusCode: 201); 9 } 10 // 請求超時 11 if (error.type == DioErrorType.CONNECT_TIMEOUT) { 12 ShowToast.warning("網絡請求超時,請稍後重試"); 13 errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT; 14 } 15 // 請求鏈接超時 16 else if (error.type == DioErrorType.RECEIVE_TIMEOUT) { 17 ShowToast.warning("網絡鏈接超時,請稍後重試"); 18 errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT; 19 } 20 // 服務器錯誤 21 else if (error.type == DioErrorType.RESPONSE) { 22 ShowToast.warning("服務器繁忙,請稍後重試"); 23 errorResponse.statusCode = ResultCode.RESPONSE; 24 } 25 // 通常服務器錯誤 26 else { 27 ShowToast.warning("網絡鏈接不可用,請稍後重試1"); 28 errorResponse.statusCode = ResultCode.DEFAULT; 29 } 30 return errorResponse; 31 }
第六步:GET方式請求
1 /// Make http request with options. 2 /// [method] The request method. 3 /// [path] The url path. 4 /// [data] The request data 5 /// [options] The request options. 6 /// String 返回 json data . 7 Future<Map> request<T>( 8 String path, { 9 String method = Method.get, 10 String contentType= "application/json; charset=utf-8", 11 queryParameters, 12 Options options, 13 // CancelToken cancelToken, 14 }) async { 15 print('path===' + path); 16 Response response = await _dio.request( 17 path, 18 queryParameters: queryParameters, 19 options: _checkOptions(method, contentType, options), 20 // cancelToken: cancelToken, 21 ); 22 _printHttpLog(response); 23 if (response.statusCode == 200) { 24 try { 25 if (response.data is Map) { 26 if (response.data["httpCode"] != 200) { 27 ShowToast.warning(response.data["message"]); 28 return new Future.error(new DioError( 29 response: response, 30 type: DioErrorType.RESPONSE, 31 )); 32 } 33 // 因爲不一樣的接口返回的格式不固定不規範,因此須要根據接口格式自定義. 34 return response.data['data']; 35 } else { 36 if (response.data is List) { 37 Map<String, dynamic> _dataMap = Map(); 38 _dataMap["data"] = response.data; 39 return _dataMap; 40 } 41 } 42 } catch (e) { 43 ShowToast.warning("網絡鏈接不可用,請稍後重試"); 44 return new Future.error(new DioError( 45 response: response, 46 // message: "data parsing exception...", 47 type: DioErrorType.RESPONSE, 48 )); 49 } 50 } 51 ShowToast.warning("網絡鏈接不可用,請稍後重試"); 52 return new Future.error(new DioError( 53 response: response, 54 type: DioErrorType.RESPONSE, 55 )); 56 }
第七步:POST方式請求-json傳值
1 /// Make http request with options. 2 /// [method] The request method. 3 /// [path] The url path. 4 /// [data] The request data 5 /// [options] The request options. 6 /// String 返回 json data . 7 Future<Map> request<T>( 8 String path, { 9 String method = Method.get, 10 String contentType= "application/json; charset=utf-8", 11 queryParameters, 12 Options options, 13 // CancelToken cancelToken, 14 }) async { 15 print('path===' + path); 16 Response response; 17 if (method == Method.get) { 18 //GET方式 19 20 ... 21 22 } else { 23 //除GET的其餘方式 24 var requestData = queryParameters; 25 response = await _dio.request( 26 path, 27 data: requestData, 28 options: _checkOptions(method, contentType, options), 29 // cancelToken: cancelToken, 30 ); 31 } 32 33 _printHttpLog(response); 34 if (response.statusCode == 200) { 35 36 ... 37 38 } 39 40 ... 41 42 }
第八步:POST方式請求-表單傳值
1 //if (contentType == 'application/x-www-form-urlencoded') {//表單方式 2 var requestData = new FormData.fromMap({ 3 "name": "jackson影琪", 4 "age": 25, 5 });
第九步:請求日誌處理
1 // print Http Log. 2 void _printHttpLog(Response response) { 3 print(!_isDebug); 4 if (!_isDebug) { 5 return; 6 } 7 try { 8 print("----------------Http Log Start----------------" + 9 _getOptionsStr(response.request)); 10 print(response); 11 print("----------------Http Log end----------------"); 12 } catch (ex) { 13 print("Http Log" + " error......"); 14 } 15 } 16 17 // get Options Str. 18 String _getOptionsStr(RequestOptions request) { 19 return "method: " + 20 request.method + 21 " baseUrl: " + 22 request.baseUrl + 23 " path: " + 24 request.path; 25 }
第10步:完整代碼
1 import 'dart:async'; 2 import 'package:dio/dio.dart'; 3 import 'ShowToastUtils.dart'; 4 5 class DioNetUtils { 6 static final DioNetUtils _singleton = DioNetUtils._init(); 7 static Dio _dio; 8 9 /// 是不是debug模式. 10 static bool _isDebug = true; 11 12 /// 打開debug模式. 13 static void openDebug() { 14 _isDebug = true; 15 } 16 17 DioNetUtils._init() { 18 BaseOptions options = new BaseOptions( 19 baseUrl: "http://192.168.1.19:8880", 20 connectTimeout: 1000 * 1, 21 receiveTimeout: 1000 * 2, 22 //Http請求頭. 23 headers: { 24 //do something 25 "version": "1.0.0" 26 }, 27 //請求的Content-Type,默認值是"application/json; charset=utf-8". 也能夠用"application/x-www-form-urlencoded" 28 // contentType: "application/json; charset=utf-8", 29 //表示指望以那種格式(方式)接受響應數據。接受4種類型 `json`, `stream`, `plain`, `bytes`. 默認值是 `json`, 30 responseType: ResponseType.json, 31 ); 32 _dio = Dio(options); 33 //添加攔截器 34 _dio.interceptors 35 .add(InterceptorsWrapper(onRequest: (RequestOptions options) { 36 print("請求以前處理"); 37 return options; //continue 38 }, onResponse: (Response response) { 39 print("響應以前處理"); 40 print(options); 41 return response; // continue 42 }, onError: (DioError e) { 43 print("錯誤以前提示"); 44 Response errorInfo = _dealErrorInfo(e); 45 return errorInfo; //continue 46 })); 47 } 48 49 factory DioNetUtils() { 50 return _singleton; 51 } 52 53 /// Make http request with options. 54 /// [method] The request method. 55 /// [path] The url path. 56 /// [data] The request data 57 /// [options] The request options. 58 /// String 返回 json data . 59 Future<Map> request<T>( 60 String path, { 61 String method = Method.get, 62 String contentType= "application/json; charset=utf-8", 63 queryParameters, 64 Options options, 65 // CancelToken cancelToken, 66 }) async { 67 print('path===' + path); 68 Response response; 69 if (method == Method.get) { 70 //GET方式 71 response = await _dio.request( 72 path, 73 queryParameters: queryParameters, 74 options: _checkOptions(method, contentType, options), 75 // cancelToken: cancelToken, 76 ); 77 } else { 78 //除GET的其餘方式 79 var requestData; 80 print(contentType); 81 if (contentType == 'application/x-www-form-urlencoded') {//表單方式 82 requestData = new FormData.fromMap({ 83 "name": "jackson影琪", 84 "age": 25, 85 }); 86 }else{//json格式 87 requestData = queryParameters; 88 } 89 response = await _dio.request( 90 path, 91 data: requestData, 92 options: _checkOptions(method, contentType, options), 93 // cancelToken: cancelToken, 94 ); 95 } 96 97 _printHttpLog(response); 98 if (response.statusCode == 200) { 99 try { 100 if (response.data is Map) { 101 if (response.data["httpCode"] != 200) { 102 ShowToast.warning(response.data["message"]); 103 return new Future.error(new DioError( 104 response: response, 105 type: DioErrorType.RESPONSE, 106 )); 107 } 108 // 因爲不一樣的接口返回的格式不固定不規範,因此須要根據接口格式自定義. 109 return response.data['data']; 110 } else { 111 if (response.data is List) { 112 Map<String, dynamic> _dataMap = Map(); 113 _dataMap["data"] = response.data; 114 return _dataMap; 115 } 116 } 117 } catch (e) { 118 ShowToast.warning("網絡鏈接不可用,請稍後重試"); 119 return new Future.error(new DioError( 120 response: response, 121 // message: "data parsing exception...", 122 type: DioErrorType.RESPONSE, 123 )); 124 } 125 } 126 ShowToast.warning("網絡鏈接不可用,請稍後重試"); 127 return new Future.error(new DioError( 128 response: response, 129 type: DioErrorType.RESPONSE, 130 )); 131 } 132 133 /// check Options. 134 Options _checkOptions(method, contentType, options) { 135 if (options == null) { 136 options = new Options(); 137 } 138 // if (contentType) { 139 // //設置請求的類型 json 表單 140 // options.contentType = contentType; 141 // } 142 options.method = method; 143 return options; 144 } 145 146 // print Http Log. 147 void _printHttpLog(Response response) { 148 print(!_isDebug); 149 if (!_isDebug) { 150 return; 151 } 152 try { 153 print("----------------Http Log Start----------------" + 154 _getOptionsStr(response.request)); 155 print(response); 156 print("----------------Http Log end----------------"); 157 } catch (ex) { 158 print("Http Log" + " error......"); 159 } 160 } 161 162 // get Options Str. 163 String _getOptionsStr(RequestOptions request) { 164 return "method: " + 165 request.method + 166 " baseUrl: " + 167 request.baseUrl + 168 " path: " + 169 request.path; 170 } 171 172 // 錯誤全局處理 173 _dealErrorInfo(error) { 174 print(error.type); 175 // 請求錯誤處理 176 Response errorResponse; 177 if (error.response != null) { 178 errorResponse = error.response; 179 } else { 180 errorResponse = new Response(statusCode: 201); 181 } 182 // 請求超時 183 if (error.type == DioErrorType.CONNECT_TIMEOUT) { 184 ShowToast.warning("網絡請求超時,請稍後重試"); 185 errorResponse.statusCode = ResultCode.CONNECT_TIMEOUT; 186 } 187 // 請求鏈接超時 188 else if (error.type == DioErrorType.RECEIVE_TIMEOUT) { 189 ShowToast.warning("網絡鏈接超時,請稍後重試"); 190 errorResponse.statusCode = ResultCode.RECEIVE_TIMEOUT; 191 } 192 // 服務器錯誤 193 else if (error.type == DioErrorType.RESPONSE) { 194 ShowToast.warning("服務器繁忙,請稍後重試"); 195 errorResponse.statusCode = ResultCode.RESPONSE; 196 } 197 // 通常服務器錯誤 198 else { 199 ShowToast.warning("網絡鏈接不可用,請稍後重試1"); 200 errorResponse.statusCode = ResultCode.DEFAULT; 201 } 202 return errorResponse; 203 } 204 } 205 206 abstract class DioCallback<T> { 207 void onSuccess(T t); 208 209 void onError(DioError error); 210 }
** dio網絡請求失敗的回調錯誤碼 **
1 /* 2 * dio網絡請求失敗的回調錯誤碼 自定義 3 */ 4 class ResultCode { 5 //正常返回是1 6 static const SUCCESS = 1; 7 8 //異常返回是0 9 static const ERROR = 0; 10 11 /// When opening url timeout, it occurs. 12 static const CONNECT_TIMEOUT = -1; 13 14 ///It occurs when receiving timeout. 15 static const RECEIVE_TIMEOUT = -2; 16 17 /// When the server response, but with a incorrect status, such as 404, 503... 18 static const RESPONSE = -3; 19 20 /// When the request is cancelled, dio will throw a error with this type. 21 static const CANCEL = -4; 22 23 /// read the DioError.error if it is not null. 24 static const DEFAULT = -5; 25 }
** dio網絡請求方式 **
1 /// 請求方法. 2 class Method { 3 static const String get = "GET"; 4 static final String post = "POST"; 5 static final String put = "PUT"; 6 static final String head = "HEAD"; 7 static final String delete = "DELETE"; 8 static final String patch = "PATCH"; 9 }
1,頁面調用
1 Map<String, String> params = Map(); 2 params['loginCode'] = _unameController.text; 3 params['password'] = _pwdController.text; 4 NetUtils.post(ServiceApi.loginAction, params: params).then((data) { 5 print(ServiceApi.loginAction); 6 print(data); 7 }).catchError((e) { 8 Toast.toast( 9 context, 10 msg: '網絡請求出錯:$e,請稍後重試!', 11 position: 'top', 12 bgColor: Color.fromRGBO(130, 0, 0, 1), // Color 提示框背景顏色 13 textColor: Color.fromRGBO(250, 100, 100, 1), // Color 提示框文字顏色 14 ); 15 });
1,服務接口地址
1 import 'dart:async'; 2 3 import '../util/DioNetUtils.dart'; 4 5 class ServiceNetApi { 6 ///獲取用戶信息 7 Future<Map> getSingleDataById(data) async { 8 return await DioNetUtils().request<String>( 9 "/**/**/yingqi/**/getSingleDataById", 10 queryParameters: data, 11 method:Method.put 12 ); 13 } 14 }
2,頁面調用
1 void getData() async { 2 Map<String, String> params = Map(); 3 params['Id'] = "123456789"; 4 params['Name'] = "jackson影琪"; 5 await ServiceNetApi().getSingleDataById(params).then((json) { 6 print('getSingleDataById'); 7 print(json); 8 }).catchError((e) { 9 10 }); 11 }
3,返回的結果