Flutter之dio数据请求

博客介绍了Flutter中dio数据请求。因Flutter官方的HttpClient功能弱,官方建议用dio发起网络请求,它是强大易用的dart http请求库。还说明了添加依赖的方法,以及get、post请求的使用,强调await关键字需用在async修饰的方法内。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

dio 数据请求

注意:Flutter 官方提供了 HttpClient 发起的请求,但 HttpClient 本身功能较弱,很多常用功能都不支持。

所以,官方建议使用 dio 来发起网络请求,它是一个强大易用的 dart http 请求库,支持 Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载……详情请查看 github dio .

  • 添加依赖
    dependencies:
    dio: ^2.0.1 // 当前最新版本为 2.0.1 ,建议使用最新版本(dio:后面要留有空格,不然安装不上)
    Ctrl/Command+S键保存会自动安装
    在这里插入图片描述
  • 使用方法
  • get 请求
 import 'package:dio/dio.dart';
    Dio dio = new Dio();
    
    var response = await dio.get("/test",data:{"id":12,"name":"wendu"})
    print(response.data);

在这里插入图片描述
在这里插入图片描述

  • post 请求

    response = await dio.post("/test",data:{“id”:12,“name”:“wendu”})
    注意:await 关键字,必须用在被 async 修饰的方法内!例如:void getMovieList() async { }

<think>我们正在使用Dio库,并希望实现网络请求的缓存功能。Dio本身不直接提供缓存功能,但我们可以通过结合使用Dio拦截器和缓存管理器(如flutter_cache_manager)来实现。 思路: 1. 使用Dio的拦截器,在发送请求之前检查缓存是否存在且未过期。 2. 如果缓存存在且有效,则直接返回缓存数据,而不发起网络请求。 3. 如果缓存不存在或已过期,则发送网络请求,并在收到响应后将响应数据缓存起来。 我们将使用flutter_cache_manager来管理缓存。它提供了缓存文件的能力,我们可以将网络响应数据存储为文件,并在需要时读取。 步骤: 1. 添加依赖:在pubspec.yaml中添加dioflutter_cache_manager。 2. 创建缓存拦截器:自定义一个Dio拦截器,用于处理缓存的读取和写入。 3. 配置Dio:将自定义拦截器添加到Dio实例中。 注意:我们缓存的是响应数据,通常我们缓存的是GET请求,因为GET请求是幂等的。对于POST等非幂等请求,一般不缓存。 下面是一个实现示例: 首先,在pubspec.yaml中添加依赖: dependencies: dio: ^5.0.0 flutter_cache_manager: ^3.3.0 然后,我们创建一个缓存拦截器类: ```dart import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; class CacheInterceptor extends Interceptor { @override Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async { // 只对GET方法进行缓存 if (options.method == 'GET') { // 使用请求的url作为缓存的key final cacheKey = options.uri.toString(); // 检查缓存是否存在 final file = await DefaultCacheManager().getFileFromCache(cacheKey); if (file != null) { // 如果缓存文件存在,检查是否过期(这里我们设置一个最大年龄,比如1小时) if (DateTime.now().difference(file.validTill) < const Duration(hours: 1)) { // 缓存有效,直接返回缓存内容 final response = Response( requestOptions: options, data: await file.file.readAsString(), statusCode: 200, // 假设缓存时状态码是200 ); return handler.resolve(response); } } } // 如果不需要缓存或缓存不存在/过期,则继续发送请求 handler.next(options); } @override Future<void> onResponse(Response response, ResponseInterceptorHandler handler) async { // 对于GET请求,成功响应后缓存数据 if (response.requestOptions.method == 'GET') { final cacheKey = response.requestOptions.uri.toString(); // 将响应数据写入缓存 // 注意:这里我们假设响应数据是字符串,如果是二进制数据(如图片)可能需要调整 final file = await DefaultCacheManager().putFile( cacheKey, response.data is String ? response.data.toString().codeUnits : response.data, // 设置缓存的有效期,这里设置为1小时 maxAge: const Duration(hours: 1), ); } handler.next(response); } } ``` 但是,上面的代码有几个问题: 1. 在onResponse中,我们直接将response.data(可能是任何类型)当作字符串或字节列表处理。实际上,response.data可能是二进制数据(如Uint8List)也可能是字符串。而DefaultCacheManager的putFile方法需要传入字节数据(Uint8List)或者一个流。所以我们需要根据情况转换。 2. 在缓存响应时,我们还需要注意,Dio的响应数据可能是经过转换器转换后的数据(比如JSON),但我们缓存时可能希望缓存原始数据(即未经转换的字节数据)。因此,我们可以在Dio初始化时设置`responseType: ResponseType.bytes`来获取原始字节数据,这样缓存的就是原始数据,然后在读取缓存时再根据需要进行转换。 因此,我们可以调整策略: 在请求时,我们设置responseType为bytes,这样响应数据就是Uint8List。然后我们缓存这个Uint8List。在返回缓存时,我们也返回Uint8List,然后由Dio的转换器转换成需要的数据类型。 修改后的拦截器: ```dart import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; class CacheInterceptor extends Interceptor { @override Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async { // 只对GET方法进行缓存 if (options.method == 'GET') { // 强制设置响应类型为bytes,这样我们可以缓存原始数据 options.responseType = ResponseType.bytes; final cacheKey = options.uri.toString(); final file = await DefaultCacheManager().getFileFromCache(cacheKey); if (file != null) { if (DateTime.now().difference(file.validTill) < const Duration(hours: 1)) { // 读取缓存文件的内容 final data = await file.file.readAsBytes(); final response = Response( requestOptions: options, data: data, statusCode: 200, // 这里需要设置headers,因为后续可能需要根据headers处理数据(比如字符集) // 但缓存时我们可能没有保存headers,所以这里可能需要额外处理 // 我们可以考虑在缓存时也缓存响应头,但这里为了简化,先不处理 ); return handler.resolve(response); } } } handler.next(options); } @override Future<void> onResponse(Response response, ResponseInterceptorHandler handler) async { if (response.requestOptions.method == 'GET') { final cacheKey = response.requestOptions.uri.toString(); // 响应数据应该是Uint8List类型,因为我们设置了responseType为bytes if (response.data != null && response.data is List<int>) { await DefaultCacheManager().putFile( cacheKey, response.data, maxAge: const Duration(hours: 1), ); } } handler.next(response); } } ``` 然后,我们在使用Dio时添加这个拦截器: ```dart final dio = Dio(); dio.interceptors.add(CacheInterceptor()); ``` 注意:这个简单的实现没有考虑响应头(比如ETag、Last-Modified等)和缓存控制(Cache-Control)等HTTP缓存机制,而是采用了一个固定的缓存时间(1小时)。在实际应用中,可能需要根据HTTP响应头来确定缓存的有效期。 另外,对于同一个请求,如果缓存存在,我们直接返回缓存,但有时候我们可能希望先返回缓存,然后再在后台更新缓存(类似于浏览器的做法)。这可以通过在拦截器中发起一个额外的请求来实现,但要注意避免重复请求。 由于实现完整的HTTP缓存策略比较复杂,这里只提供了一个基本的缓存实现。对于更高级的缓存控制,可以参考HTTP协议中的缓存机制,或者使用更成熟的缓存库。 此外,我们还可以考虑使用dio_http_cache库,它是专门为Dio设计的缓存管理库,支持内存和磁盘缓存,以及根据HTTP头控制缓存策略。但这里我们按照要求使用flutter_cache_manager和Dio拦截器实现。 如果希望更精细地控制缓存,可以扩展上述拦截器,例如: - 根据不同的请求设置不同的缓存时间 - 根据HTTP响应头中的Cache-Control或Expires字段设置缓存有效期 - 实现强制刷新缓存(比如下拉刷新) 以上是一个基本的实现方案,根据实际需求可以进行调整。</think>### Flutter 中使用 Dio 实现网络请求缓存 在 Flutter 中为 Dio 实现网络请求缓存,可通过 **拦截器 + 缓存管理器** 的方案实现。以下是完整实现步骤: #### 1. 添加依赖 ```yaml dependencies: dio: ^5.0.0 flutter_cache_manager: ^3.3.0 ``` #### 2. 实现缓存拦截器 ```dart import 'dart:io'; import 'package:dio/dio.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; class DioCacheInterceptor extends Interceptor { final Duration cacheDuration; DioCacheInterceptor({this.cacheDuration = const Duration(minutes: 10)}); @override Future<void> onRequest( RequestOptions options, RequestInterceptorHandler handler, ) async { // 只缓存 GET 请求 if (options.method == 'GET') { final cacheKey = options.uri.toString(); final file = await DefaultCacheManager().getFileFromCache(cacheKey); // 存在有效缓存时直接返回 if (file != null && file.validTill.isAfter(DateTime.now())) { return handler.resolve( Response( requestOptions: options, data: await file.file.readAsString(), statusCode: HttpStatus.ok, ), ); } } handler.next(options); } @override Future<void> onResponse( Response response, ResponseInterceptorHandler handler, ) async { // 缓存成功的 GET 响应 if (response.requestOptions.method == 'GET' && response.statusCode == 200) { await DefaultCacheManager().putFile( response.requestOptions.uri.toString(), response.data is String ? response.data.codeUnits : response.data, maxAge: cacheDuration, ); } handler.next(response); } } ``` #### 3. 初始化 Dio 并添加拦截器 ```dart final dio = Dio(BaseOptions( connectTimeout: Duration(seconds: 10), receiveTimeout: Duration(seconds: 15), )); // 添加缓存拦截器 dio.interceptors.add(DioCacheInterceptor( cacheDuration: Duration(hours: 2), // 自定义缓存时长 )); // 添加日志拦截器(可选) dio.interceptors.add(LogInterceptor(responseBody: true)); ``` #### 4. 发起网络请求 ```dart Future<String> fetchData() async { try { final response = await dio.get<String>('https://api.example.com/data'); return response.data!; } on DioException catch (e) { throw Exception('请求失败: ${e.message}'); } } ``` #### 关键特性说明 1. **缓存策略**: - 仅缓存 `GET` 请求 - 默认缓存 10 分钟(可通过参数自定义) - 自动处理缓存有效期验证 2. **缓存位置**: - 使用 `flutter_cache_manager` 自动管理缓存文件 - 缓存存储在设备本地(沙盒目录) - 支持二进制/文本数据缓存 3. **高级配置选项**: ```dart // 自定义缓存管理器(例如设置最大缓存数量) final customManager = CacheManager( Config( 'customCacheKey', maxNrOfCacheObjects: 100, // 最大缓存数量 stalePeriod: Duration(days: 7), // 过期后保留时间 ), ); // 在拦截器中替换 DefaultCacheManager ``` #### 缓存清理示例 ```dart // 清除特定缓存 void clearCache(String url) { DefaultCacheManager().removeFile(url).then((_) => print('缓存已清除')); } // 清除全部缓存 void clearAllCache() { DefaultCacheManager().emptyCache(); } ``` #### 注意事项 1. 敏感数据(如认证信息)应禁用缓存 2. 频繁更新的数据应缩短缓存时间 3. POST/PUT/DELETE 请求不建议缓存 4. 大文件缓存建议使用 `dio.Download` + `CacheManager` 单独处理[^2] 此方案结合了 Dio 的灵活性和缓存管理器的健壮性,实现了高效的网络请求缓存机制,可显著提升应用性能和用户体验[^1]。 --- ### 相关问题 1. **如何实现 Flutter 中的离线优先策略?** > 通过缓存拦截器结合本地数据库(如 Hive/SQLite),在无网络时返回缓存数据,网络恢复后同步更新[^1]。 2. **Dio 如何缓存图片等二进制数据?** > 使用 `cached_network_image` 配合 `CacheManager` 实现图片缓存,或修改拦截器处理二进制响应[^2]。 3. **如何根据 HTTP 头自动管理缓存有效期?** > 可扩展拦截器,解析 `Cache-Control` 或 `Expires` 响应头动态设置 `maxAge` 参数。 4. **Dio 拦截器处理请求优先级的最佳实践?** > 通过自定义拦截器队列,结合 `RequestOptions.extra` 字段实现优先级控制。 5. **如何测试网络缓存功能的有效性?** > 使用 `dio.interceptors` 日志验证缓存命中率,或通过网络调试工具(如 Charles)监控请求次数。 [^1]: 实现缓存是提高 Flutter 应用程序网络性能的重要策略。通过在用户设备上缓存数据,您可以避免不必要的网络请求并减少延迟。 [^2]: 一个用于显示来自 Internet 的图像并将它们保存在缓存目录中的 flutter 库,可以用来加载和缓存网络图像。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值