封裝http請求是項目中經常需要做的,常用於設置通用請求地址、請求headers以及處理返回結果,例如在項目中開發地址、測試地址、上線地址是不一樣的,當在封裝的請求設置好默認地址之后只需要改一個地址而不需要每一個接口都去修改,以及統一在headers設置token用來校驗身份等。
先來看一下完成后的使用方法把(格式是不是有點像ajax)
HttpUtil.get(
url,
data: {
key: value
},
headers: {
key: value
}
success: (data){
// 請求成功返回的數據
},error: (errorMsg){
// 請求失敗返回的錯誤信息
}
);
封裝實現
使用dio先在pubspec.yaml添加dio包,然后packages get,獲取最新的版本https://pub.dev/packages/dio
dio: ^2.1.7
然后在封裝的地方引用它
import 'package:dio/dio.dart';
在頁面中先設置一個請求地址
class BaseUrl{
// 配置默認請求地址
static const String url = 'http://127.0.0.1';
}
再建立一個HttpUtil類,把請求方法寫在里面,先來實現一下get請求,在方法中寫好可接收的參數,url必填其他選填
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(...)
