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,或者userIdif (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
//初始化的时候从持久化储存中获取cookiestatic 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();}}}}}//清除cookiestatic 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