request的使用

12147

使用的包(DIO)

Flutter的DIO是一个用于HTTP请求的强大插件,允许开发人员轻松进行RESTful API调用和文件上传/下载等操作。它提供了许多功能,例如支持异步请求和响应处理、拦截器、进度条、全局通用配置、统一状态管理和取消请求等。DIO的主要特点是它非常易于使用和学习,同时还提供了一些高级特性用于处理复杂请求场景。开发人员可以使用DIO插件轻松地实现网络请求并处理响应以获取API数据,这使得Flutter应用程序与Web服务器等API可以轻松地通信。

以下是一个简单的DIO代码片段,作为演示使用:

  1. import 'dart:convert';
  2. import 'package:dio/dio.dart';
  3. void main() async {
  4. try {
  5. Response response = await Dio().get('<https://jsonplaceholder.typicode.com/todos/1>');
  6. print(response.data);
  7. } catch (e) {
  8. print(e);
  9. }
  10. }

在这个代码片段中,我们导入DIO插件并在主函数中发送一个HTTP GET请求。我们在URL中传递一个API端点,并使用await操作符等待响应(Response)。一旦响应被接收,我们通过调用response.data来获取响应结果。这里我们假设API返回JSON格式并使用Dart内置的JSON解析库将其转换为相应的Dart对象。

当然,这只是一个非常简单的示例。DIO提供了许多更强大和灵活的功能,例如自定义拦截器、文件上传/下载、Https支持等,可以满足更多复杂的请求场景。

项目中的示例

代码来源:jianghuAppBrowser/jianghuBrowser/lib/Utils/DioUtil.dart

  1. //请求拦截器
  2. dioClient.interceptors.add(InterceptorsWrapper(onRequest: (RequestOptions requestOptions, RequestInterceptorHandler requestInterceptorHandler) async {
  3. //此处可网络请求之前做相关配置,比如会所有请求添加token,或者userId
  4. if (Constants.hostUri != null) {
  5. await AuthUtil.saveCookie();
  6. }
  7. debugPrint("=== ✅ cookie ${AuthUtil.cookieMap.value}");
  8. Map<String, dynamic> cookie = AuthUtil.cookieMap.value;
  9. requestOptions.headers.addAll(cookie);
  10. requestInterceptorHandler.next(requestOptions);
  11. }, onResponse: (Response response, ResponseInterceptorHandler handler) {
  12. debugPrint("=== ✅ response ${response}");
  13. handler.next(response);
  14. }, onError: (DioError e, ErrorInterceptorHandler handler) {
  15. debugPrint("=== ❌ DioError ${e.requestOptions.data}");
  16. debugPrint("=== ❌ DioError $e");
  17. handler.next(e);
  18. }));
  19. //封装jianghuAxios请求
  20. static Future<Map?> resource(String pageId, String actionId, {Map? where, Map? actionData, List? whereIn}) async {
  21. if(Constants.resourceUrl != null) {
  22. final Map data = {
  23. 'packageId': '${DateTime.now().toIso8601String()}_${Random(1000000).nextInt(9999999)}',
  24. 'packageType': 'httpRequest',
  25. 'appData': {
  26. 'appId': Constants.appId.value,
  27. 'userAgent': Constants.userAgent,
  28. 'pageId': pageId,
  29. 'actionId': actionId,
  30. 'authToken': Constants.authToken,
  31. 'where': where ?? {},
  32. 'actionData': actionData ?? {},
  33. 'whereIn': whereIn
  34. }
  35. };
  36. try {
  37. Response result = await dioClient.post(Constants.resourceUrl!, data: data);
  38. return result.data['appData']['resultData'];
  39. } catch (error) {
  40. return null;
  41. }
  42. }
  43. }

Flutter的DIO提供了简单的方式来管理cookie,可以通过设置Dio的cookieJar属性来实现。cookieJar是一个存储和管理cookie的抽象类,Dart HTTP库实现了它的两个具体实现:CookieJar和PresistentCookieJar。

CookieJar是在内存中管理cookie的实现,这意味着当应用程序退出时cookie会被清除。PersistentCookieJar是将cookie持久化到本地磁盘的实现,这意味着cookie将持久化存储并在应用程序下一次启动时恢复。

以下是一个使用PersistentCookieJar的示例:

  1. import 'package:dio/dio.dart';
  2. import 'package:dio_cookie_manager/dio_cookie_manager.dart';
  3. import 'package:cookie_jar/cookie_jar.dart';
  4. void main() async {
  5. var dio = Dio();
  6. var cookieJar=PersistCookieJar(dir: './my_cookie/');
  7. dio.interceptors.add(CookieManager(cookieJar));
  8. await dio.get("<https://www.google.com>");
  9. await dio.get("<https://www.baidu.com>");
  10. List<Cookie> cookies=await cookieJar.loadForRequest(Uri.parse('<https://www.google.com>'));
  11. print('Cookies of google: $cookies');
  12. }

在这个示例中,我们首先创建了一个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

  1. //初始化的时候从持久化储存中获取cookie
  2. static initCookie() async {
  3. if(Constants.hostUri?.host.isNotEmpty??false) {
  4. await Prefs.reload();
  5. List<String> cookie = Prefs.getStringList('${Constants.appId.value}_cookie');
  6. Constants.authToken = Prefs.getString('${Constants.appId.value}_authToken');
  7. print("cookies initCookie $cookie ${Constants.appId.value}");
  8. if(cookie.length > 2) {
  9. cookieName = cookie[0];
  10. cookieValue = cookie[1];
  11. cookieDomain = cookie[2];
  12. cookieMap.value['Cookie'] = "$cookieName=$cookieValue";
  13. cookieMap.value = {...cookieMap.value};
  14. }
  15. }
  16. }
  17. //从web端获取cookie,并存于app端
  18. static Future<void> saveCookie() async {
  19. if(RenderKey.hostUrl.value != null) {
  20. List<Cookie> cookies = await cookieManager.getCookies(RenderKey.hostUrl.value);
  21. for (Cookie item in cookies) {
  22. if (item.domain == Constants.hostUri!.host) {
  23. cookieValue = item.value;
  24. cookieName = item.name;
  25. cookieDomain = item.domain;
  26. if (cookieValue != null) {
  27. cookieMap.value.putIfAbsent('Cookie', () => "$cookieName=$cookieValue");
  28. cookieMap.value = {...cookieMap.value};
  29. Prefs.setStringList('${Constants.appId.value}_cookie', [cookieName!, cookieValue!, Constants.hostUri!.host]);
  30. await Prefs.reload();
  31. }
  32. }
  33. }
  34. }
  35. }
  36. //清除cookie
  37. static clearCookie() async {
  38. cookieName = null;
  39. cookieValue = null;
  40. cookieDomain = null;
  41. cookieMap.value = {
  42. 'Cookie': ''
  43. };
  44. cookieManager.clearCookies();
  45. if(Constants.hostUri?.host.isNotEmpty??false) {
  46. await Prefs.remove('${Constants.appId.value}_cookie');
  47. await Prefs.reload();
  48. }
  49. }

下载、上传

Flutter的DIO插件提供了上传和下载文件的功能,非常适用于文件的读写操作。下面我们来简单介绍一下原理和使用方式。

上传文件

要上传文件,我们需要将文件转换为相应的二进制数据。DIO提供FormData对象来实现上传操作。使用FormData对象,我们可以将文件或文件列表添加到表单数据中。

以下是一个上传文件的简单示例:

  1. import 'dart:io';
  2. import 'package:dio/dio.dart';
  3. void main() async {
  4. var dio = Dio();
  5. var formData = FormData.fromMap({
  6. 'file': await MultipartFile.fromFile('./image.png', filename: 'image.png'),
  7. });
  8. var response = await dio.post('<https://your-api.com/upload>', data: formData);
  9. print(response.statusCode);
  10. }

在这个示例中,我们首先创建一个Dio实例,并使用FormData.fromMap方法构造一个包含文件路径的Map对象。接着我们创建了一个MultipartFile对象,用于将文件转换为可上传的格式。最后我们将构造好的formData作为参数传递给post方法,发送HTTP请求,并接收响应结果。

下载文件

DIO提供了大量的配置选项来自定义文件下载的行为,例如设置超时时间、请求头、下载进度回调等。使用Dio的download方法,我们可以轻松地下载文件到本地存储设备。

以下是一个下载文件的简单示例:

  1. import 'dart:io';
  2. import 'package:dio/dio.dart';
  3. void main() async {
  4. var dio = Dio();
  5. var savePath = './download/file.zip';
  6. await dio.download('<https://your-api.com/file.zip>', savePath,
  7. onReceiveProgress: (received, total) {
  8. if (total != -1) {
  9. print('${(received / total * 100).floor()}%');
  10. }
  11. });
  12. print('Download completed');
  13. }

在这个示例中,我们首先创建一个Dio实例,并指定保存文件的路径。接着我们使用Dio的download方法,传递请求的URI和文件保存路径作为参数。同时,我们也使用onReceiveProgress参数,以便在下载过程中实时收到回调以获取下载进度信息。

项目中的示例

代码来源:/jianghuAppBrowser/jianghuBrowser/lib/Utils/DownloadUtil.dart

  1. Future<String?> downloadFile(String fileUrl, String filename, {bool mustDelete = false, Function? onReceiveProgress}) async {
  2. try {
  3. int? next = await FileUtil.checkAndTipsFileActions(fileUrl, filename, delete: mustDelete);
  4. if (next == 0) {
  5. return await DownloadUtil.downloadFileChannel(
  6. downloadPath: fileUrl,
  7. fileName: filename,
  8. onReceiveProgress: onReceiveProgress
  9. );
  10. } else if (next == null) {
  11. FileUtil.webCancelDownloadProgress();
  12. return null;
  13. } if (next == 1) {
  14. FileUtil.webCancelDownloadProgress();
  15. return FileUtil.getFullPath(filename);
  16. }
  17. } catch (err) {
  18. FileUtil.webCancelDownloadProgress();
  19. debugPrint("下载异常A::$err");
  20. return null;
  21. }
  22. return null;
  23. }

分片上传

参考:/jianghuAppBrowser/jianghuBrowser/lib/Utils/UploadUtil.dart