在Flutter專案中使用網路請求的方式大致可分為兩種,分別是Dart原生的網路請求 HttpClient類以及第三方開源的網路請求庫。在Dart社群開源的第三方http請求庫中Flutter中文網開源的Dio庫人氣最高。
下面我們先來比較下這兩種網路請求方式,然後再看怎麼基於 Dio庫封裝方便使用的網路請求工具類HttpManager。
網路請求庫比較
HttClient類
Dart IO庫中提供了用於發起Http請求的一些類,我們可以直接使用HttpClient來發起請求。使用HttpClient發起請求分為五步:
- 建立一個HttpClient
HttpClient httpClient = new HttpClient();
複製程式碼
- 開啟Http連線,設定請求頭
HttpClientRequest request = await httpClient.getUrl(uri);
複製程式碼
這一步可以使用任意Http Method,如httpClient.post(...)、httpClient.delete(...)等。如果包含Query引數,可以在構建uri時新增,如:
Uri uri=Uri(scheme: "https", host: "flutterchina.club", queryParameters: {
"xx":"xx",
"yy":"dd"
});
複製程式碼
通過HttpClientRequest可以設定請求header,如:
request.headers.add("user-agent", "test");
複製程式碼
如果是post或put等可以攜帶請求體方法,可以通過HttpClientRequest物件傳送request body,如:
String payload="...";
request.add(utf8.encode(payload));
//request.addStream(_inputStream); //可以直接新增輸入流
複製程式碼
- 等待連線伺服器
HttpClientResponse response = await request.close();
複製程式碼
這一步完成後,請求資訊就已經傳送給伺服器了,返回一個HttpClientResponse物件,它包含響應頭(header)和響應流(響應體的Stream),接下來就可以通過讀取響應流來獲取響應內容。
- 讀取響應內容
String responseBody = await response.transform(utf8.decoder).join();
複製程式碼
我們通過讀取響應流來獲取伺服器返回的資料,在讀取時我們可以設定編碼格式,這裡是utf8。
- 請求結束,關閉HttpClient
httpClient.close();
複製程式碼
關閉client後,通過該client發起的所有請求都會中止。
以上的步驟是dart原生網路HttpClient使用方式,可以發現直接使用HttpClient發起網路請求是比較麻煩的,很多事情都得手動處理,如果再涉及到檔案上傳/下載、Cookie管理等就會變得非常繁瑣,並且HttpClient本身功能較弱,很多常用功能都不支援。
Dio庫
dio是一個強大的Dart Http請求庫,支援Restful API、FormData、攔截器、請求取消、Cookie管理、檔案上傳/下載、超時等...
- pubspec.yaml 新增依賴
dependencies:
dio: ^x.x.x #請使用pub上的最新版本
複製程式碼
- 匯入引用並建立dio 例項
import 'package:dio/dio.dart';
Dio dio = Dio();
複製程式碼
接下來就可以通過 dio例項來發起網路請求了,注意,一個dio例項可以發起多個http請求,一般來說,APP只有一個http資料來源時,dio應該使用單例模式。
- 發起網路請求
Get 請求
Response response;
response=await dio.get("/test?id=12&name=cheney")
print(response.data.toString());
複製程式碼
Post請求
Response response;
response=await dio.post("/test",data:{"id":12,"name":"cheney"})
print(response.data.toString());
複製程式碼
以上就是Dio庫網路請求的基本使用,是不是很簡單,除了這些基本的用法,dio還支援請求配置、攔截器等,官方資料比較詳細,故在這裡不再贅述,詳情可以參考dio主頁:github.com/flutterchin… 。
封裝Dio工具類
為什麼要封裝 dio
做一些公共處理,方便靈活的使用。
做那些封裝
- 統一處理請求字首;(www.xx.com/api/v1 不用每個請求都加字首)
- 統一輸出請求或響應資訊;
- 統一錯誤資訊處理;
- 相容多種網路請求、支援檔案上傳、下載;
- 支援同步回撥與非同步Future 兩種形式
- 返回資料自動轉json格式並預設解析公共資料模型;
目錄
類名 | 描述 |
---|---|
HttpManager | 網路請求管理類 |
HttpError | 網路請求統一錯誤類 |
LogInterceptor | 網路請求工具類 |
HttpManager
import 'dart:core';
import 'package:connectivity/connectivity.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_common_utils/http/http_error.dart';
import 'package:flutter_common_utils/log_util.dart';
///http請求成功回撥
typedef HttpSuccessCallback<T> = void Function(dynamic data);
///失敗回撥
typedef HttpFailureCallback = void Function(HttpError data);
///資料解析回撥
typedef T JsonParse<T>(dynamic data);
/// @desc 封裝 http 請求
/// @time 2019/3/15 10:35 AM
/// @author Cheney
class HttpManager {
///同一個CancelToken可以用於多個請求,當一個CancelToken取消時,所有使用該CancelToken的請求都會被取消,一個頁面對應一個CancelToken。
Map<String, CancelToken> _cancelTokens = Map<String, CancelToken>();
///超時時間
static const int CONNECT_TIMEOUT = 30000;
static const int RECEIVE_TIMEOUT = 30000;
/// http request methods
static const String GET = 'get';
static const String POST = 'post';
Dio _client;
static final HttpManager _instance = HttpManager._internal();
factory HttpManager() => _instance;
Dio get client => _client;
/// 建立 dio 例項物件
HttpManager._internal() {
if (_client == null) {
/// 全域性屬性:請求字首、連線超時時間、響應超時時間
BaseOptions options = BaseOptions(
connectTimeout: CONNECT_TIMEOUT,
receiveTimeout: RECEIVE_TIMEOUT,
);
_client = Dio(options);
}
}
///初始化公共屬性
///
/// [baseUrl] 地址字首
/// [connectTimeout] 連線超時趕時間
/// [receiveTimeout] 接收超時趕時間
/// [interceptors] 基礎攔截器
void init(
{String baseUrl,
int connectTimeout,
int receiveTimeout,
List<Interceptor> interceptors}) {
_client.options = _client.options.merge(
baseUrl: baseUrl,
connectTimeout: connectTimeout,
receiveTimeout: receiveTimeout,
);
if (interceptors != null && interceptors.isNotEmpty) {
_client.interceptors..addAll(interceptors);
}
}
///Get網路請求
///
///[url] 網路請求地址不包含域名
///[params] url請求引數支援restful
///[options] 請求配置
///[successCallback] 請求成功回撥
///[errorCallback] 請求失敗回撥
///[tag] 請求統一標識,用於取消網路請求
void get({
@required String url,
Map<String, dynamic> params,
Options options,
HttpSuccessCallback successCallback,
HttpFailureCallback errorCallback,
@required String tag,
}) async {
_request(
url: url,
params: params,
method: GET,
successCallback: successCallback,
errorCallback: errorCallback,
tag: tag,
);
}
///post網路請求
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[successCallback] 請求成功回撥
///[errorCallback] 請求失敗回撥
///[tag] 請求統一標識,用於取消網路請求
void post({
@required String url,
data,
Map<String, dynamic> params,
Options options,
HttpSuccessCallback successCallback,
HttpFailureCallback errorCallback,
@required String tag,
}) async {
_request(
url: url,
data: data,
method: POST,
params: params,
successCallback: successCallback,
errorCallback: errorCallback,
tag: tag,
);
}
///統一網路請求
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[successCallback] 請求成功回撥
///[errorCallback] 請求失敗回撥
///[tag] 請求統一標識,用於取消網路請求
void _request({
@required String url,
String method,
data,
Map<String, dynamic> params,
Options options,
HttpSuccessCallback successCallback,
HttpFailureCallback errorCallback,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
if (errorCallback != null) {
errorCallback(HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
LogUtil.v("請求網路異常,請稍後重試!");
return;
}
//設定預設值
params = params ?? {};
method = method ?? 'GET';
options?.method = method;
options = options ??
Options(
method: method,
);
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
Response<Map<String, dynamic>> response = await _client.request(url,
data: data,
queryParameters: params,
options: options,
cancelToken: cancelToken);
String statusCode = response.data["statusCode"];
if (statusCode == "0") {
//成功
if (successCallback != null) {
successCallback(response.data["data"]);
}
} else {
//失敗
String message = response.data["statusDesc"];
LogUtil.v("請求伺服器出錯:$message");
if (errorCallback != null) {
errorCallback(HttpError(statusCode, message));
}
}
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
if (errorCallback != null && e.type != DioErrorType.CANCEL) {
errorCallback(HttpError.dioError(e));
}
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
if (errorCallback != null) {
errorCallback(HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
}
///下載檔案
///
///[url] 下載地址
///[savePath] 檔案儲存路徑
///[onReceiveProgress] 檔案儲存路徑
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[successCallback] 請求成功回撥
///[errorCallback] 請求失敗回撥
///[tag] 請求統一標識,用於取消網路請求
void download({
@required String url,
@required savePath,
ProgressCallback onReceiveProgress,
Map<String, dynamic> params,
data,
Options options,
HttpSuccessCallback successCallback,
HttpFailureCallback errorCallback,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
if (errorCallback != null) {
errorCallback(HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
LogUtil.v("請求網路異常,請稍後重試!");
return;
}
////0代表不設定超時
int receiveTimeout = 0;
options ??= options == null
? Options(receiveTimeout: receiveTimeout)
: options.merge(receiveTimeout: receiveTimeout);
//設定預設值
params = params ?? {};
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
Response response = await _client.download(url, savePath,
onReceiveProgress: onReceiveProgress,
queryParameters: params,
data: data,
options: options,
cancelToken: cancelToken);
//成功
if (successCallback != null) {
successCallback(response.data);
}
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
if (errorCallback != null && e.type != DioErrorType.CANCEL) {
errorCallback(HttpError.dioError(e));
}
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
if (errorCallback != null) {
errorCallback(HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
}
///上傳檔案
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[onSendProgress] 上傳進度
///[params] url請求引數支援restful
///[options] 請求配置
///[successCallback] 請求成功回撥
///[errorCallback] 請求失敗回撥
///[tag] 請求統一標識,用於取消網路請求
void upload({
@required String url,
FormData data,
ProgressCallback onSendProgress,
Map<String, dynamic> params,
Options options,
HttpSuccessCallback successCallback,
HttpFailureCallback errorCallback,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
if (errorCallback != null) {
errorCallback(HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
LogUtil.v("請求網路異常,請稍後重試!");
return;
}
//設定預設值
params = params ?? {};
//強制 POST 請求
options?.method = POST;
options = options ??
Options(
method: POST,
);
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
Response<Map<String, dynamic>> response = await _client.request(url,
onSendProgress: onSendProgress,
data: data,
queryParameters: params,
options: options,
cancelToken: cancelToken);
String statusCode = response.data["statusCode"];
if (statusCode == "0") {
//成功
if (successCallback != null) {
successCallback(response.data["data"]);
}
} else {
//失敗
String message = response.data["statusDesc"];
LogUtil.v("請求伺服器出錯:$message");
if (errorCallback != null) {
errorCallback(HttpError(statusCode, message));
}
}
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
if (errorCallback != null && e.type != DioErrorType.CANCEL) {
errorCallback(HttpError.dioError(e));
}
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
if (errorCallback != null) {
errorCallback(HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
}
///GET非同步網路請求
///
///[url] 網路請求地址不包含域名
///[params] url請求引數支援restful
///[options] 請求配置
///[tag] 請求統一標識,用於取消網路請求
Future<T> getAsync<T>({
@required String url,
Map<String, dynamic> params,
Options options,
JsonParse<T> jsonParse,
@required String tag,
}) async {
return _requestAsync(
url: url,
method: GET,
params: params,
options: options,
jsonParse: jsonParse,
tag: tag,
);
}
///POST 非同步網路請求
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[tag] 請求統一標識,用於取消網路請求
Future<T> postAsync<T>({
@required String url,
data,
Map<String, dynamic> params,
Options options,
JsonParse<T> jsonParse,
@required String tag,
}) async {
return _requestAsync(
url: url,
method: POST,
data: data,
params: params,
options: options,
jsonParse: jsonParse,
tag: tag,
);
}
///統一網路請求
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[tag] 請求統一標識,用於取消網路請求
Future<T> _requestAsync<T>({
@required String url,
String method,
data,
Map<String, dynamic> params,
Options options,
JsonParse<T> jsonParse,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
LogUtil.v("請求網路異常,請稍後重試!");
throw (HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
//設定預設值
params = params ?? {};
method = method ?? 'GET';
options?.method = method;
options = options ??
Options(
method: method,
);
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
Response<Map<String, dynamic>> response = await _client.request(url,
queryParameters: params,
data: data,
options: options,
cancelToken: cancelToken);
String statusCode = response.data["statusCode"];
if (statusCode == "0") {
//成功
if (jsonParse != null) {
return jsonParse(response.data["data"]);
} else {
return response.data["data"];
}
} else {
//失敗
String message = response.data["statusDesc"];
LogUtil.v("請求伺服器出錯:$message");
//只能用 Future,外層有 try catch
return Future.error((HttpError(statusCode, message)));
}
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
throw (HttpError.dioError(e));
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
throw (HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
///非同步下載檔案
///
///[url] 下載地址
///[savePath] 檔案儲存路徑
///[onReceiveProgress] 檔案儲存路徑
///[data] post 請求引數
///[params] url請求引數支援restful
///[options] 請求配置
///[tag] 請求統一標識,用於取消網路請求
Future<Response> downloadAsync({
@required String url,
@required savePath,
ProgressCallback onReceiveProgress,
Map<String, dynamic> params,
data,
Options options,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
LogUtil.v("請求網路異常,請稍後重試!");
throw (HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
//設定下載不超時
int receiveTimeout = 0;
options ??= options == null
? Options(receiveTimeout: receiveTimeout)
: options.merge(receiveTimeout: receiveTimeout);
//設定預設值
params = params ?? {};
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
return _client.download(url, savePath,
onReceiveProgress: onReceiveProgress,
queryParameters: params,
data: data,
options: options,
cancelToken: cancelToken);
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
throw (HttpError.dioError(e));
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
throw (HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
///上傳檔案
///
///[url] 網路請求地址不包含域名
///[data] post 請求引數
///[onSendProgress] 上傳進度
///[params] url請求引數支援restful
///[options] 請求配置
///[tag] 請求統一標識,用於取消網路請求
Future<T> uploadAsync<T>({
@required String url,
FormData data,
ProgressCallback onSendProgress,
Map<String, dynamic> params,
Options options,
JsonParse<T> jsonParse,
@required String tag,
}) async {
//檢查網路是否連線
ConnectivityResult connectivityResult =
await (Connectivity().checkConnectivity());
if (connectivityResult == ConnectivityResult.none) {
LogUtil.v("請求網路異常,請稍後重試!");
throw (HttpError(HttpError.NETWORK_ERROR, "網路異常,請稍後重試!"));
}
//設定預設值
params = params ?? {};
//強制 POST 請求
options?.method = POST;
options = options ??
Options(
method: POST,
);
url = _restfulUrl(url, params);
try {
CancelToken cancelToken;
if (tag != null) {
cancelToken =
_cancelTokens[tag] == null ? CancelToken() : _cancelTokens[tag];
_cancelTokens[tag] = cancelToken;
}
Response<Map<String, dynamic>> response = await _client.request(url,
onSendProgress: onSendProgress,
data: data,
queryParameters: params,
options: options,
cancelToken: cancelToken);
String statusCode = response.data["statusCode"];
if (statusCode == "0") {
//成功
if (jsonParse != null) {
return jsonParse(response.data["data"]);
} else {
return response.data["data"];
}
} else {
//失敗
String message = response.data["statusDesc"];
LogUtil.v("請求伺服器出錯:$message");
return Future.error((HttpError(statusCode, message)));
}
} on DioError catch (e, s) {
LogUtil.v("請求出錯:$e\n$s");
throw (HttpError.dioError(e));
} catch (e, s) {
LogUtil.v("未知異常出錯:$e\n$s");
throw (HttpError(HttpError.UNKNOWN, "網路異常,請稍後重試!"));
}
}
///取消網路請求
void cancel(String tag) {
if (_cancelTokens.containsKey(tag)) {
if (!_cancelTokens[tag].isCancelled) {
_cancelTokens[tag].cancel();
}
_cancelTokens.remove(tag);
}
}
///restful處理
String _restfulUrl(String url, Map<String, dynamic> params) {
// restful 請求處理
// /gysw/search/hist/:user_id user_id=27
// 最終生成 url 為 /gysw/search/hist/27
params.forEach((key, value) {
if (url.indexOf(key) != -1) {
url = url.replaceAll(':$key', value.toString());
}
});
return url;
}
}
複製程式碼
這裡內建了網路是否連線判斷、取消網路請求、處理了預設的資料格式為
{
"data":{},
"statusCode":"0",
"statusDesc":"02032008:使用者授信未通過",
"timestamp":1569206576392
}
複製程式碼
大家可根據自己的需求自行更改成自己的資料格式處理
HttpError
import 'package:dio/dio.dart';
/// @desc 網路請求錯誤
/// @time 2019/3/20 10:02 AM
/// @author Cheney
class HttpError {
///HTTP 狀態碼
static const int UNAUTHORIZED = 401;
static const int FORBIDDEN = 403;
static const int NOT_FOUND = 404;
static const int REQUEST_TIMEOUT = 408;
static const int INTERNAL_SERVER_ERROR = 500;
static const int BAD_GATEWAY = 502;
static const int SERVICE_UNAVAILABLE = 503;
static const int GATEWAY_TIMEOUT = 504;
///未知錯誤
static const String UNKNOWN = "UNKNOWN";
///解析錯誤
static const String PARSE_ERROR = "PARSE_ERROR";
///網路錯誤
static const String NETWORK_ERROR = "NETWORK_ERROR";
///協議錯誤
static const String HTTP_ERROR = "HTTP_ERROR";
///證書錯誤
static const String SSL_ERROR = "SSL_ERROR";
///連線超時
static const String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
///響應超時
static const String RECEIVE_TIMEOUT = "RECEIVE_TIMEOUT";
///傳送超時
static const String SEND_TIMEOUT = "SEND_TIMEOUT";
///網路請求取消
static const String CANCEL = "CANCEL";
String code;
String message;
HttpError(this.code, this.message);
HttpError.dioError(DioError error) {
message = error.message;
switch (error.type) {
case DioErrorType.CONNECT_TIMEOUT:
code = CONNECT_TIMEOUT;
message = "網路連線超時,請檢查網路設定";
break;
case DioErrorType.RECEIVE_TIMEOUT:
code = RECEIVE_TIMEOUT;
message = "伺服器異常,請稍後重試!";
break;
case DioErrorType.SEND_TIMEOUT:
code = SEND_TIMEOUT;
message = "網路連線超時,請檢查網路設定";
break;
case DioErrorType.RESPONSE:
code = HTTP_ERROR;
message = "伺服器異常,請稍後重試!";
break;
case DioErrorType.CANCEL:
code = CANCEL;
message = "請求已被取消,請重新請求";
break;
case DioErrorType.DEFAULT:
code = UNKNOWN;
message = "網路異常,請稍後重試!";
break;
}
}
@override
String toString() {
return 'HttpError{code: $code, message: $message}';
}
}
複製程式碼
這裡設定的多種錯誤的描述,大家可根據需求自行修改
LogInterceptor
import 'package:dio/dio.dart';
import 'package:flutter_common_utils/log_util.dart';
void log2Console(Object object) {
LogUtil.v(object);
}
/// @desc 自定義日誌攔截器
///@time 2019/3/18 9:15 AM
/// @author Cheney
class LogInterceptor extends Interceptor {
LogInterceptor({
this.request = true,
this.requestHeader = true,
this.requestBody = false,
this.responseHeader = true,
this.responseBody = false,
this.error = true,
this.logPrint = log2Console,
});
/// Print request [Options]
bool request;
/// Print request header [Options.headers]
bool requestHeader;
/// Print request data [Options.data]
bool requestBody;
/// Print [Response.data]
bool responseBody;
/// Print [Response.headers]
bool responseHeader;
/// Print error message
bool error;
/// Log printer; defaults print log to console.
/// In flutter, you'd better use debugPrint.
/// you can also write log in a file, for example:
///```dart
/// var file=File("./log.txt");
/// var sink=file.openWrite();
/// dio.interceptors.add(LogInterceptor(logPrint: sink.writeln));
/// ...
/// await sink.close();
///```
void Function(Object object) logPrint;
@override
Future onRequest(RequestOptions options) async {
logPrint('*** Request ***');
printKV('uri', options.uri);
if (request) {
printKV('method', options.method);
printKV('responseType', options.responseType?.toString());
printKV('followRedirects', options.followRedirects);
printKV('connectTimeout', options.connectTimeout);
printKV('receiveTimeout', options.receiveTimeout);
printKV('extra', options.extra);
}
if (requestHeader) {
logPrint('headers:');
options.headers.forEach((key, v) => printKV(" $key", v));
}
if (requestBody) {
logPrint("data:");
printAll(options.data);
}
logPrint("");
}
@override
Future onError(DioError err) async {
if (error) {
logPrint('*** DioError ***:');
logPrint("uri: ${err.request.uri}");
logPrint("$err");
if (err.response != null) {
_printResponse(err.response);
}
logPrint("");
}
}
@override
Future onResponse(Response response) async {
logPrint("*** Response ***");
_printResponse(response);
}
void _printResponse(Response response) {
printKV('uri', response.request?.uri);
if (responseHeader) {
printKV('statusCode', response.statusCode);
if (response.isRedirect == true) {
printKV('redirect', response.realUri);
}
if (response.headers != null) {
logPrint("headers:");
response.headers.forEach((key, v) => printKV(" $key", v.join(",")));
}
}
if (responseBody) {
logPrint("Response Text:");
printAll(response.toString());
}
logPrint("");
}
printKV(String key, Object v) {
logPrint('$key: $v');
}
printAll(msg) {
msg.toString().split("\n").forEach(logPrint);
}
}
複製程式碼
這裡預設使用 LogUtl 輸出日誌,大家可根據需要換成自己的日誌輸出工具類
使用示例
Step1: 初始化
//初始化 Http,
HttpManager().init(
baseUrl: Api.getBaseUrl(),
interceptors: [
HeaderInterceptor(),
LogInterceptor(),
],
);
複製程式碼
Step2:建立網路請求
///同步回撥模式
///get 網路請求
void _get(){
HttpManager().get(
url: "/app/info",
params: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///post 網路請求
void _post(){
HttpManager().post(
url: "/app/info",
data: {"iouCode": iouCode},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: "tag",
);
}
///下載檔案
void _download(){
HttpManager().download(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
tag: tag,
);
}
///上傳檔案
void _upload() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
HttpManager().upload(
url: "/app/upload",
data: data,
tag: "tag",
successCallback: (data) {
},
errorCallback: (HttpError error) {
},
);
}
///非同步模式
///get 請求
void _getAysnc() async{
String timestamp =
await HttpManager().getAsync(url: "/app/info", tag: "syncTime");
}
///post 請求
void _postAysnc() async{
await HttpManager().postAsync(
url: "app/info",
tag: "tag",
data: {
'bannerTypes': ["wealthBanner"],
},
jsonParse: (json) => Pager(json, (data) => ImageAd(data)))
}
///下載檔案
void _downloadAsync() async{
await HttpManager().downloadAsync(
url: "/app/download",
savePath: "/savePath",
onReceiveProgress: (int count, int total) {
},
tag: "tag",
);
}
///上傳檔案
void _uploadAsync() async{
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(path, filename: "$photoTime"),
});
await HttpManager().uploadAsync(
url: "/app/upload",
data: data,
tag: "tag",
);
}
複製程式碼
最後
如果在使用過程遇到問題,歡迎下方留言交流。