request的使用
12147使用的包(DIO)
Flutter的DIO是一个用于HTTP请求的强大插件,允许开发人员轻松进行RESTful API调用和文件上传/下载等操作。它提供了许多功能,例如支持异步请求和响应处理、拦截器、进度条、全局通用配置、统一状态管理和取消请求等。DIO的主要特点是它非常易于使用和学习,同时还提供了一些高级特性用于处理复杂请求场景。开发人员可以使用DIO插件轻松地实现网络请求并处理响应以获取API数据,这使得Flutter应用程序与Web服务器等API可以轻松地通信。
以下是一个简单的DIO代码片段,作为演示使用:
import 'dart:convert';
import 'package:dio/dio.dart';
void main() async {
try {
Response response = await Dio().get('<https://jsonplaceholder.typicode.com/todos/1>');
print(response.data);
} catch (e) {
print(e);
}
}
在这个代码片段中,我们导入DIO插件并在主函数中发送一个HTTP GET请求。我们在URL中传递一个API端点,并使用await操作符等待响应(Response)。一旦响应被接收,我们通过调用response.data来获取响应结果。这里我们假设API返回JSON格式并使用Dart内置的JSON解析库将其转换为相应的Dart对象。
当然,这只是一个非常简单的示例。DIO提供了许多更强大和灵活的功能,例如自定义拦截器、文件上传/下载、Https支持等,可以满足更多复杂的请求场景。
项目中的示例
代码来源:jianghuAppBrowser/jianghuBrowser/lib/Utils/DioUtil.dart
//请求拦截器
dioClient.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions requestOptions, RequestInterceptorHandler requestInterceptorHandler) async {
//此处可网络请求之前做相关配置,比如会所有请求添加token,或者userId
if (Constants.hostUri != null) {
await AuthUtil.saveCookie();
}
debugPrint("=== ✅ cookie ${AuthUtil.cookieMap.value}");
Map<String, dynamic> cookie = AuthUtil.cookieMap.value;
requestOptions.headers.addAll(cookie);
requestInterceptorHandler.next(requestOptions);
}, onResponse: (Response response, ResponseInterceptorHandler handler) {
debugPrint("=== ✅ response ${response}");
handler.next(response);
}, onError: (DioError e, ErrorInterceptorHandler handler) {
debugPrint("=== ❌ DioError ${e.requestOptions.data}");
debugPrint("=== ❌ DioError $e");
handler.next(e);
}));
//封装jianghuAxios请求
static Future<Map?> resource(String pageId, String actionId, {Map? where, Map? actionData, List? whereIn}) async {
if(Constants.resourceUrl != null) {
final Map data = {
'packageId': '${DateTime.now().toIso8601String()}_${Random(1000000).nextInt(9999999)}',
'packageType': 'httpRequest',
'appData': {
'appId': Constants.appId.value,
'userAgent': Constants.userAgent,
'pageId': pageId,
'actionId': actionId,
'authToken': Constants.authToken,
'where': where ?? {},
'actionData': actionData ?? {},
'whereIn': whereIn
}
};
try {
Response result = await dioClient.post(Constants.resourceUrl!, data: data);
return result.data['appData']['resultData'];
} catch (error) {
return null;
}
}
}
cookie
Flutter的DIO提供了简单的方式来管理cookie,可以通过设置Dio的cookieJar属性来实现。cookieJar是一个存储和管理cookie的抽象类,Dart HTTP库实现了它的两个具体实现:CookieJar和PresistentCookieJar。
CookieJar是在内存中管理cookie的实现,这意味着当应用程序退出时cookie会被清除。PersistentCookieJar是将cookie持久化到本地磁盘的实现,这意味着cookie将持久化存储并在应用程序下一次启动时恢复。
以下是一个使用PersistentCookieJar的示例:
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:cookie_jar/cookie_jar.dart';
void main() async {
var dio = Dio();
var cookieJar=PersistCookieJar(dir: './my_cookie/');
dio.interceptors.add(CookieManager(cookieJar));
await dio.get("<https://www.google.com>");
await dio.get("<https://www.baidu.com>");
List<Cookie> cookies=await cookieJar.loadForRequest(Uri.parse('<https://www.google.com>'));
print('Cookies of google: $cookies');
}
在这个示例中,我们首先创建了一个Dio实例和一个PersistentCookieJar实例,并将它添加到Dio实例的拦截器中,以便在每次发送请求时自动管理cookie。接着我们发送两个HTTP GET请求(谷歌和百度)以检查cookie的使用情况。最后,我们使用cookieJar.loadForRequest(Uri uri)方法来检索在发送请求时发送到服务器的cookie对象列表,并输出其结果。
注意,我们在创建PersistentCookieJar实例时指定了一个目录,因为cookie会被保存在该目录下。在默认情况下,Dart实现的CookieJar和PersistentCookieJar将不会携带任何cookie,可以通过setCookie方法添加Cookie。通过以上方式,我们就可以使用Dio插件添加和管理我们的cookie了。
项目中的示例
代码来源:/jianghuAppBrowser/jianghuBrowser/lib/Utils/AuthUtil.dart
//初始化的时候从持久化储存中获取cookie
static initCookie() async {
if(Constants.hostUri?.host.isNotEmpty??false) {
await Prefs.reload();
List<String> cookie = Prefs.getStringList('${Constants.appId.value}_cookie');
Constants.authToken = Prefs.getString('${Constants.appId.value}_authToken');
print("cookies initCookie $cookie ${Constants.appId.value}");
if(cookie.length > 2) {
cookieName = cookie[0];
cookieValue = cookie[1];
cookieDomain = cookie[2];
cookieMap.value['Cookie'] = "$cookieName=$cookieValue";
cookieMap.value = {...cookieMap.value};
}
}
}
//从web端获取cookie,并存于app端
static Future<void> saveCookie() async {
if(RenderKey.hostUrl.value != null) {
List<Cookie> cookies = await cookieManager.getCookies(RenderKey.hostUrl.value);
for (Cookie item in cookies) {
if (item.domain == Constants.hostUri!.host) {
cookieValue = item.value;
cookieName = item.name;
cookieDomain = item.domain;
if (cookieValue != null) {
cookieMap.value.putIfAbsent('Cookie', () => "$cookieName=$cookieValue");
cookieMap.value = {...cookieMap.value};
Prefs.setStringList('${Constants.appId.value}_cookie', [cookieName!, cookieValue!, Constants.hostUri!.host]);
await Prefs.reload();
}
}
}
}
}
//清除cookie
static clearCookie() async {
cookieName = null;
cookieValue = null;
cookieDomain = null;
cookieMap.value = {
'Cookie': ''
};
cookieManager.clearCookies();
if(Constants.hostUri?.host.isNotEmpty??false) {
await Prefs.remove('${Constants.appId.value}_cookie');
await Prefs.reload();
}
}
下载、上传
Flutter的DIO插件提供了上传和下载文件的功能,非常适用于文件的读写操作。下面我们来简单介绍一下原理和使用方式。
上传文件
要上传文件,我们需要将文件转换为相应的二进制数据。DIO提供FormData对象来实现上传操作。使用FormData对象,我们可以将文件或文件列表添加到表单数据中。
以下是一个上传文件的简单示例:
import 'dart:io';
import 'package:dio/dio.dart';
void main() async {
var dio = Dio();
var formData = FormData.fromMap({
'file': await MultipartFile.fromFile('./image.png', filename: 'image.png'),
});
var response = await dio.post('<https://your-api.com/upload>', data: formData);
print(response.statusCode);
}
在这个示例中,我们首先创建一个Dio实例,并使用FormData.fromMap方法构造一个包含文件路径的Map对象。接着我们创建了一个MultipartFile对象,用于将文件转换为可上传的格式。最后我们将构造好的formData作为参数传递给post方法,发送HTTP请求,并接收响应结果。
下载文件
DIO提供了大量的配置选项来自定义文件下载的行为,例如设置超时时间、请求头、下载进度回调等。使用Dio的download方法,我们可以轻松地下载文件到本地存储设备。
以下是一个下载文件的简单示例:
import 'dart:io';
import 'package:dio/dio.dart';
void main() async {
var dio = Dio();
var savePath = './download/file.zip';
await dio.download('<https://your-api.com/file.zip>', savePath,
onReceiveProgress: (received, total) {
if (total != -1) {
print('${(received / total * 100).floor()}%');
}
});
print('Download completed');
}
在这个示例中,我们首先创建一个Dio实例,并指定保存文件的路径。接着我们使用Dio的download方法,传递请求的URI和文件保存路径作为参数。同时,我们也使用onReceiveProgress参数,以便在下载过程中实时收到回调以获取下载进度信息。
项目中的示例
代码来源:/jianghuAppBrowser/jianghuBrowser/lib/Utils/DownloadUtil.dart
Future<String?> downloadFile(String fileUrl, String filename, {bool mustDelete = false, Function? onReceiveProgress}) async {
try {
int? next = await FileUtil.checkAndTipsFileActions(fileUrl, filename, delete: mustDelete);
if (next == 0) {
return await DownloadUtil.downloadFileChannel(
downloadPath: fileUrl,
fileName: filename,
onReceiveProgress: onReceiveProgress
);
} else if (next == null) {
FileUtil.webCancelDownloadProgress();
return null;
} if (next == 1) {
FileUtil.webCancelDownloadProgress();
return FileUtil.getFullPath(filename);
}
} catch (err) {
FileUtil.webCancelDownloadProgress();
debugPrint("下载异常A::$err");
return null;
}
return null;
}
分片上传
参考:/jianghuAppBrowser/jianghuBrowser/lib/Utils/UploadUtil.dart