封裝http請求是項目中常常須要作的,經常使用於設置通用請求地址、請求headers以及處理返回結果,例如在項目中開發地址、測試地址、上線地址是不同的,當在封裝的請求設置好默認地址以後只須要改一個地址而不須要每個接口都去修改,以及統一在headers設置token用來校驗身份等。javascript
先來看一下完成後的使用方法把(格式是否是有點像ajax)java
HttpUtil.get( url, data: { key: value }, headers: { key: value } success: (data){ // 請求成功返回的數據 },error: (errorMsg){ // 請求失敗返回的錯誤信息 } );
使用dio先在pubspec.yaml添加dio包,而後packages get,獲取最新的版本https://pub.dev/packages/diogit
dio: ^2.1.7
而後在封裝的地方引用它github
import 'package:dio/dio.dart';
在頁面中先設置一個請求地址ajax
class BaseUrl{ // 配置默認請求地址 static const String url = 'http://127.0.0.1'; }
再創建一個HttpUtil類,把請求方法寫在裏面,先來實現一下get請求,在方法中寫好可接收的參數,url必填其餘選填json
class HttpUtil{ static void get( String url, { Map<String, dynamic> data, Map<String, dynamic> headers, Function success, Function error } ) async { // 對接收到的請求參數進行從處理 } }
在get請求中攜帶參數的用字符串拼接的形式例如:http://127.0.0.1/vod/getPlayInfo?userid=bd2439487ce6540a68ce01b8f57242eb6&number=5,因此在接收到請求攜帶的參數後若是請求參數不爲空須要對攜帶的參數其進行拼接處理後端
// 數據拼接 if(data != null && data.isNotEmpty){ StringBuffer options= new StringBuffer('?'); data.forEach((key, value){ options.write('${key}=${value}&'); }); String optionsStr = options.toString(); optionsStr = optionsStr.substring(0, optionsStr.length - 1); url += optionsStr; }
數據拼接完成以後便可發起請求,把請求寫到一個_sendRequest方法中,而後進行進一步的處理數組
// 發送get請求 await _sendRequest( url, 'get', success, headers: headers, error: error );
在寫_sendRequest方法以前先看後端返回格式,我這邊的返回格式是這樣的,當請求成功後端code返回0,失敗會返回其餘失敗碼及提示信息服務器
{ "code": 0, // int "msg": "後端返回失敗提示信息", // string "data": {} // 這多是對象,也可能數數組 }
下面來實現_sendRequest方法,當獲取到請求的url後進行判斷,若是url是以http開頭的就可認爲其是完整地址,那就直接使用傳過來的地址,若是不是以http開頭的,那就使用設置的默認地址來拼接請求地址網絡
// 請求處理 static Future _sendRequest( String url, String method, Function success, { Map<String, dynamic> data, Map<String, dynamic> headers, Function error } ) async { int _code; String _msg; var _backData; // 檢測請求地址是不是完整地址 if(!url.startsWith('http')){ url = BaseUrl.url + url; } }
發起請求
在請求以前先判斷data和headers是否爲空,而後配置dio的請求信息,查看dio更多API:https://github.com/flutterchina/dio
try{ Map<String, dynamic> dataMap = data == null ? new Map() : data; Map<String, dynamic> headersMap = headers == null ? new Map() : headers; // 配置dio請求信息 Response response; Dio dio = new Dio(); dio.options.connectTimeout = 10000; // 服務器連接超時,毫秒 dio.options.receiveTimeout = 3000; // 響應流上先後兩次接受到數據的間隔,毫秒 dio.options.headers.addAll(headersMap); // 添加headers,如需設置統一的headers信息也可在此添加 if(method == 'get'){ response = await dio.get(url); }else{ response = await dio.post(url,data: dataMap); } }catch(exception){ _handError(error, '數據請求錯誤:'+exception.toString()); }
請求結果處理
先判斷請求狀態是否爲200,不然返回請求錯誤;而後看後端返回的code是否爲0,不爲0則返回狀態嗎+錯誤信息
if(response.statusCode != 200){ _msg = '網絡請求錯誤,狀態碼:' + response.statusCode.toString(); _handError(error, _msg); return; } // 返回結果處理 Map<String, dynamic> resCallbackMap = response.data; _code = resCallbackMap['code']; _msg = resCallbackMap['msg']; _backData = resCallbackMap['data']; if(success != null){ if(_code == 0){ success(_backData); }else{ String errorMsg = _code.toString()+':'+_msg; _handError(error, errorMsg); } }
最後再寫一個返回錯誤信息的方法
// 返回錯誤信息 static Future _handError(Function errorCallback,String errorMsg){ if(errorCallback != null){ errorCallback(errorMsg); } }
完成後測試一下一個get請求,測試的json以下
{ "code": 0, "msg": "", "data": { "backResult": "返回成功啦" } }
請求代碼
HttpUtil.get( '/app_model/httptest.json', success: (data){ print(data.toString()); },error: (errorMsg){ print(errorMsg); } );
返回結果以下:
I/flutter ( 7871): {backResult: 返回成功啦}
源文件能夠到git獲取https://gitee.com/daydayfull/flutter_httputil
import 'package:dio/dio.dart'; class BaseUrl{ // 配置默認請求地址 static const String url = 'http://127.0.0.1'; } class HttpUtil{ static void get( String url, { Map<String, dynamic> data, Map<String, dynamic> headers, Function success, Function error } ) async { // 數據拼接 if(data != null && data.isNotEmpty){ StringBuffer options= new StringBuffer('?'); data.forEach((key, value){ options.write('${key}=${value}&'); }); String optionsStr = options.toString(); optionsStr = optionsStr.substring(0, optionsStr.length - 1); url += optionsStr; } // 發送get請求 await _sendRequest( url, 'get', success, headers: headers, error: error ); } static void post( String url, { Map<String, dynamic> data, Map<String, dynamic> headers, Function success, Function error } ) async { // 發送post請求 _sendRequest( url, 'post', success, data: data, headers: headers, error: error ); } // 請求處理 static Future _sendRequest( String url, String method, Function success, { Map<String, dynamic> data, Map<String, dynamic> headers, Function error } ) async { int _code; String _msg; var _backData; // 檢測請求地址是不是完整地址 if(!url.startsWith('http')){ url = BaseUrl.url + url; } try{ Map<String, dynamic> dataMap = data == null ? new Map() : data; Map<String, dynamic> headersMap = headers == null ? new Map() : headers; // 配置dio請求信息 Response response; Dio dio = new Dio(); dio.options.connectTimeout = 10000; // 服務器連接超時,毫秒 dio.options.receiveTimeout = 3000; // 響應流上先後兩次接受到數據的間隔,毫秒 dio.options.headers.addAll(headersMap); // 添加headers,如需設置統一的headers信息也可在此添加 if(method == 'get'){ response = await dio.get(url); }else{ response = await dio.post(url,data: dataMap); } if(response.statusCode != 200){ _msg = '網絡請求錯誤,狀態碼:' + response.statusCode.toString(); _handError(error, _msg); return; } // 返回結果處理 Map<String, dynamic> resCallbackMap = response.data; _code = resCallbackMap['code']; _msg = resCallbackMap['msg']; _backData = resCallbackMap['data']; if(success != null){ if(_code == 0){ success(_backData); }else{ String errorMsg = _code.toString()+':'+_msg; _handError(error, errorMsg); } } }catch(exception){ _handError(error, '數據請求錯誤:'+exception.toString()); } } // 返回錯誤信息 static Future _handError(Function errorCallback,String errorMsg){ if(errorCallback != null){ errorCallback(errorMsg); } } }
這裏只簡單寫了get和post兩個方法,在dio中提供了以下方法
Future get(...) Future post(...) Future put(...) Future delete(...) Future head(...) Future put(...) Future path(...) Future download(...)