使用DioCacheInterceptor三方库实现Flutter网络缓存
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net是Dio的缓存拦截器库,提供了强大的HTTP缓存功能,支持多种缓存策略和存储方式。通过缓存可以显著提升应用性能,减少网络请求,改善用户体验。提示:合理使用缓存可以减少网络流量,提高响应速度,支持离线访问。是Dio的HTTP缓存拦截器,提供灵活的缓存策略。特性说明优势多种策略灵活配置适应场景

前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
Dio Cache Interceptor是Dio的缓存拦截器库,提供了强大的HTTP缓存功能,支持多种缓存策略和存储方式。通过缓存可以显著提升应用性能,减少网络请求,改善用户体验。
提示:合理使用缓存可以减少网络流量,提高响应速度,支持离线访问。
一、DioCacheInterceptor三方库简介
1.1 什么是Dio Cache Interceptor
Dio Cache Interceptor是Dio的HTTP缓存拦截器,提供灵活的缓存策略。
| 特性 | 说明 | 优势 |
|---|---|---|
| 多种策略 | 灵活配置 | 适应场景 |
| 多种存储 | 内存/文件/数据库 | 可选方案 |
| 离线支持 | 缓存优先 | 用户体验 |
| 性能优化 | 减少请求 | 提升速度 |
官方文档:https://pub.dev/packages/dio_cache_interceptor
GitHub仓库:https://github.com/llfbandit/dio_cache_interceptor
1.2 缓存策略
| 策略 | 说明 | 适用场景 |
|---|---|---|
| request | 仅请求 | 实时数据 |
| forceCache | 强制缓存 | 静态资源 |
| refresh | 刷新缓存 | 更新数据 |
| refreshForceCache | 刷新并缓存 | 混合场景 |
1.3 存储方式
| 存储 | 说明 | 特点 |
|---|---|---|
| MemCacheStore | 内存 | 快速但临时 |
| FileCacheStore | 文件 | 持久化 |
| HiveCacheStore | Hive数据库 | 高性能 |
二、环境配置
2.1 添加依赖
dependencies:
dio: ^5.4.0
dio_cache_interceptor: ^3.5.0
dio_cache_interceptor_file_store: ^1.2.0
2.2 安装依赖
flutter pub get
2.3 导入包
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
import 'package:dio_cache_interceptor_file_store/dio_cache_interceptor_file_store.dart';
相关资源:
- Dio Cache Interceptor Package:https://pub.dev/packages/dio_cache_interceptor
- Dio文档:https://pub.dev/packages/dio
- HTTP缓存:https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
三、基础使用
3.1 创建缓存配置
import 'package:path_provider/path_provider.dart';
Future<CacheOptions> createCacheOptions() async {
final cacheDir = await getTemporaryDirectory();
return CacheOptions(
store: FileCacheStore(cacheDir.path),
policy: CachePolicy.request,
hitCacheOnErrorExcept: [401, 403],
maxStale: Duration(days: 7),
priority: CachePriority.normal,
cipher: null,
keyBuilder: CacheOptions.defaultCacheKeyBuilder,
allowPostMethod: false,
);
}
3.2 添加拦截器
Future<Dio> createDio() async {
final dio = Dio();
final cacheOptions = await createCacheOptions();
dio.interceptors.add(DioCacheInterceptor(options: cacheOptions));
return dio;
}
3.3 发送请求
Future<void> fetchData() async {
final dio = await createDio();
try {
final response = await dio.get('https://api.example.com/data');
print('Data: ${response.data}');
print('From cache: ${response.extra[CacheResponse.key] != null}');
} catch (e) {
print('Error: $e');
}
}
四、缓存策略
4.1 Request策略
// 默认策略:优先网络,失败时使用缓存
final response = await dio.get(
'https://api.example.com/data',
options: Options(
extra: {
CacheOptions.defaultCacheKeyBuilder: CachePolicy.request,
},
),
);
4.2 ForceCache策略
// 强制使用缓存,不发送网络请求
final response = await dio.get(
'https://api.example.com/data',
options: buildCacheOptions(
Duration(days: 7),
forceRefresh: false,
).toOptions(),
);
4.3 Refresh策略
// 强制刷新,忽略缓存
final response = await dio.get(
'https://api.example.com/data',
options: buildCacheOptions(
Duration(days: 7),
forceRefresh: true,
).toOptions(),
);
4.4 自定义策略
final cacheOptions = CacheOptions(
store: store,
policy: CachePolicy.request,
// 仅在这些错误时使用缓存
hitCacheOnErrorExcept: [401, 403, 404],
// 最大过期时间
maxStale: Duration(days: 7),
// 优先级
priority: CachePriority.high,
);
五、存储方式
5.1 内存存储
final cacheOptions = CacheOptions(
store: MemCacheStore(),
policy: CachePolicy.request,
maxStale: Duration(hours: 1),
);
5.2 文件存储
Future<CacheOptions> createFileCacheOptions() async {
final cacheDir = await getTemporaryDirectory();
return CacheOptions(
store: FileCacheStore('${cacheDir.path}/dio_cache'),
policy: CachePolicy.request,
maxStale: Duration(days: 7),
);
}
5.3 Hive存储
import 'package:dio_cache_interceptor_hive_store/dio_cache_interceptor_hive_store.dart';
import 'package:hive/hive.dart';
Future<CacheOptions> createHiveCacheOptions() async {
final cacheDir = await getApplicationDocumentsDirectory();
Hive.init(cacheDir.path);
return CacheOptions(
store: HiveCacheStore(cacheDir.path),
policy: CachePolicy.request,
maxStale: Duration(days: 30),
);
}
六、实战示例
6.1 新闻应用
class NewsService {
late Dio _dio;
Future<void> initialize() async {
_dio = Dio();
final cacheDir = await getTemporaryDirectory();
final cacheOptions = CacheOptions(
store: FileCacheStore('${cacheDir.path}/news_cache'),
policy: CachePolicy.request,
maxStale: Duration(hours: 1),
hitCacheOnErrorExcept: [401, 403],
);
_dio.interceptors.add(DioCacheInterceptor(options: cacheOptions));
}
Future<List<News>> getNews({bool forceRefresh = false}) async {
try {
final response = await _dio.get(
'https://api.example.com/news',
options: buildCacheOptions(
Duration(hours: 1),
forceRefresh: forceRefresh,
).toOptions(),
);
final fromCache = response.extra[CacheResponse.key] != null;
print('From cache: $fromCache');
return (response.data as List)
.map((json) => News.fromJson(json))
.toList();
} catch (e) {
print('Error: $e');
rethrow;
}
}
Future<News> getNewsDetail(String id) async {
final response = await _dio.get(
'https://api.example.com/news/$id',
options: buildCacheOptions(
Duration(days: 1),
).toOptions(),
);
return News.fromJson(response.data);
}
}
class News {
final String id;
final String title;
final String content;
News({
required this.id,
required this.title,
required this.content,
});
factory News.fromJson(Map<String, dynamic> json) {
return News(
id: json['id'],
title: json['title'],
content: json['content'],
);
}
}
6.2 图片缓存
class ImageCacheService {
late Dio _dio;
Future<void> initialize() async {
_dio = Dio();
final cacheDir = await getTemporaryDirectory();
final cacheOptions = CacheOptions(
store: FileCacheStore('${cacheDir.path}/image_cache'),
policy: CachePolicy.forceCache,
maxStale: Duration(days: 30),
);
_dio.interceptors.add(DioCacheInterceptor(options: cacheOptions));
}
Future<Uint8List> getImage(String url) async {
final response = await _dio.get<List<int>>(
url,
options: Options(
responseType: ResponseType.bytes,
),
);
return Uint8List.fromList(response.data!);
}
Future<void> preloadImages(List<String> urls) async {
await Future.wait(
urls.map((url) => getImage(url)),
);
}
}
6.3 API服务
class ApiService {
late Dio _dio;
late CacheStore _cacheStore;
Future<void> initialize() async {
_dio = Dio(BaseOptions(
baseUrl: 'https://api.example.com',
connectTimeout: Duration(seconds: 30),
receiveTimeout: Duration(seconds: 30),
));
final cacheDir = await getTemporaryDirectory();
_cacheStore = FileCacheStore('${cacheDir.path}/api_cache');
final cacheOptions = CacheOptions(
store: _cacheStore,
policy: CachePolicy.request,
maxStale: Duration(days: 7),
hitCacheOnErrorExcept: [401, 403],
);
_dio.interceptors.add(DioCacheInterceptor(options: cacheOptions));
}
Future<T> get<T>(
String path, {
Map<String, dynamic>? queryParameters,
Duration? cacheDuration,
bool forceRefresh = false,
}) async {
final response = await _dio.get(
path,
queryParameters: queryParameters,
options: buildCacheOptions(
cacheDuration ?? Duration(hours: 1),
forceRefresh: forceRefresh,
).toOptions(),
);
return response.data as T;
}
Future<void> clearCache() async {
await _cacheStore.clean();
}
Future<void> deleteCache(String key) async {
await _cacheStore.delete(key);
}
}
七、高级功能
7.1 自定义Key生成
String customKeyBuilder(RequestOptions request) {
// 自定义缓存key
return '${request.method}_${request.uri}_${request.data}';
}
final cacheOptions = CacheOptions(
store: store,
keyBuilder: customKeyBuilder,
);
7.2 加密缓存
import 'package:encrypt/encrypt.dart';
final key = Key.fromLength(32);
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
final cacheOptions = CacheOptions(
store: store,
cipher: CacheCipher(
encrypt: (bytes) => encrypter.encryptBytes(bytes, iv: iv).bytes,
decrypt: (bytes) => encrypter.decryptBytes(Encrypted(bytes), iv: iv),
),
);
7.3 缓存优先级
// 高优先级缓存
final highPriority = CacheOptions(
store: store,
priority: CachePriority.high,
maxStale: Duration(days: 30),
);
// 低优先级缓存
final lowPriority = CacheOptions(
store: store,
priority: CachePriority.low,
maxStale: Duration(hours: 1),
);
7.4 条件缓存
final cacheOptions = CacheOptions(
store: store,
policy: CachePolicy.request,
// 仅缓存GET请求
allowPostMethod: false,
// 特定状态码才缓存
hitCacheOnErrorExcept: [400, 401, 403, 404, 500],
);
八、缓存管理
8.1 清除缓存
class CacheManager {
final CacheStore store;
CacheManager(this.store);
// 清除所有缓存
Future<void> clearAll() async {
await store.clean();
}
// 清除过期缓存
Future<void> clearExpired() async {
await store.clean(staleOnly: true);
}
// 删除特定缓存
Future<void> delete(String key) async {
await store.delete(key);
}
// 检查缓存是否存在
Future<bool> exists(String key) async {
final response = await store.get(key);
return response != null;
}
}
8.2 缓存统计
class CacheStats {
final CacheStore store;
CacheStats(this.store);
Future<Map<String, dynamic>> getStats() async {
// 实现缓存统计逻辑
return {
'totalSize': 0,
'itemCount': 0,
'hitRate': 0.0,
};
}
}
8.3 缓存预热
class CacheWarmer {
final Dio dio;
CacheWarmer(this.dio);
Future<void> warmup(List<String> urls) async {
await Future.wait(
urls.map((url) => dio.get(url)),
);
}
}
九、性能优化
9.1 内存缓存优先
class TieredCacheStore implements CacheStore {
final MemCacheStore memCache;
final FileCacheStore fileCache;
TieredCacheStore(this.memCache, this.fileCache);
Future<CacheResponse?> get(String key) async {
// 先查内存
var response = await memCache.get(key);
if (response != null) return response;
// 再查文件
response = await fileCache.get(key);
if (response != null) {
// 写入内存缓存
await memCache.set(response);
}
return response;
}
Future<void> set(CacheResponse response) async {
await Future.wait([
memCache.set(response),
fileCache.set(response),
]);
}
// 实现其他方法...
}
9.2 压缩缓存
import 'dart:io';
final cacheOptions = CacheOptions(
store: store,
// 使用gzip压缩
cipher: CacheCipher(
encrypt: (bytes) => gzip.encode(bytes),
decrypt: (bytes) => gzip.decode(bytes),
),
);
9.3 限制缓存大小
class SizeLimitedCacheStore implements CacheStore {
final CacheStore delegate;
final int maxSizeBytes;
int currentSize = 0;
SizeLimitedCacheStore(this.delegate, this.maxSizeBytes);
Future<void> set(CacheResponse response) async {
final size = response.content?.length ?? 0;
if (currentSize + size > maxSizeBytes) {
await clean(staleOnly: true);
}
await delegate.set(response);
currentSize += size;
}
// 实现其他方法...
}
十、最佳实践
10.1 分类缓存
class CacheConfig {
static CacheOptions shortTerm() {
return CacheOptions(
store: MemCacheStore(),
maxStale: Duration(minutes: 5),
);
}
static Future<CacheOptions> mediumTerm() async {
final dir = await getTemporaryDirectory();
return CacheOptions(
store: FileCacheStore('${dir.path}/medium_cache'),
maxStale: Duration(hours: 1),
);
}
static Future<CacheOptions> longTerm() async {
final dir = await getApplicationDocumentsDirectory();
return CacheOptions(
store: FileCacheStore('${dir.path}/long_cache'),
maxStale: Duration(days: 30),
);
}
}
10.2 错误处理
Future<Response> cachedRequest(String url) async {
try {
return await dio.get(url);
} on DioException catch (e) {
if (e.type == DioExceptionType.connectionTimeout ||
e.type == DioExceptionType.receiveTimeout) {
// 超时时使用缓存
return await dio.get(
url,
options: buildCacheOptions(
Duration(days: 7),
forceRefresh: false,
).toOptions(),
);
}
rethrow;
}
}
10.3 缓存策略选择
CachePolicy selectPolicy(String endpoint) {
if (endpoint.contains('/static/')) {
return CachePolicy.forceCache;
} else if (endpoint.contains('/realtime/')) {
return CachePolicy.refresh;
} else {
return CachePolicy.request;
}
}
十一、常见问题
11.1 缓存未生效
检查:
- 缓存策略是否正确
- 存储路径是否有权限
- 是否添加了拦截器
11.2 缓存占用过大
定期清理:
// 定期清理过期缓存
Timer.periodic(Duration(hours: 24), (_) async {
await store.clean(staleOnly: true);
});
11.3 离线访问失败
使用forceCache策略:
final response = await dio.get(
url,
options: buildCacheOptions(
Duration(days: 7),
forceRefresh: false,
).toOptions(),
);
十三、性能优化(第二轮)
第二轮缓存优化的核心目标是:更高命中率 + 更低额外开销 + 更可控的缓存体积。缓存不是“开了就快”,需要用数据闭环来治理。
13.1 先建立可观测指标
| 指标 | 含义 | 建议实现 |
|---|---|---|
| hitRate | 命中率 | 统计fromCache比例 |
| staleRate | 过期命中率 | 统计maxStale相关行为 |
| cacheSize | 缓存占用 | 定期扫描目录/Store统计 |
| p95Latency | 95分位耗时 | 拦截器打点聚合 |

13.2 按接口类型选择策略(减少误用)
| 接口类型 | 推荐策略 | 说明 |
|---|---|---|
| 静态配置/字典 | forceCache |
高命中、低频更新 |
| 列表页 | request + maxStale |
兼顾实时与体验 |
| 实时数据 | refresh |
强一致优先 |
十四、内存优化(第二轮)
缓存的内存优化重点是“可控体积”:限制缓存大小、定期清理、避免缓存大对象。
14.1 给缓存加上限(按大小/按条数)
class CountLimitedStore implements CacheStore {
final CacheStore delegate;
final int maxCount;
CountLimitedStore(this.delegate, {required this.maxCount});
Future<void> set(CacheResponse response) async {
// TODO: 真实实现需要维护索引/时间戳
await delegate.set(response);
}
Future<CacheResponse?> get(String key) => delegate.get(key);
Future<void> delete(String key) => delegate.delete(key);
Future<void> clean({bool staleOnly = false}) => delegate.clean(staleOnly: staleOnly);
}
14.2 清理策略建议
- App启动时清理一次过期缓存
- 每24小时清理过期缓存
- 当缓存目录超过阈值时触发清理

十五、问题定位与排障(第二轮)
缓存类问题常见三类:
- 缓存没命中:key不一致/策略不对/未写入
- 缓存脏数据:过期策略不合理/forceCache误用
- 缓存占用过大:未清理/资源类响应缓存过大
15.1 判断响应是否来自缓存
final fromCache = response.extra[CacheResponse.key] != null;
print('fromCache=' + fromCache.toString() + ' url=' + response.requestOptions.uri.toString());
15.2 缓存key排查
- 打印
CacheOptions.defaultCacheKeyBuilder(requestOptions)结果 - 确保同一接口的query/body不会导致key不断变化
15.3 抓包对齐(缓存命中时是否还发请求)

十六、总结
本文详细介绍了Dio Cache Interceptor三方库的使用方法,包括缓存策略、存储方式、实战示例等。合理使用缓存可以显著提升应用性能,改善用户体验。
Dio Cache Interceptor的主要优势:
- 多种缓存策略,灵活配置
- 多种存储方式,按需选择
- 支持离线访问
- 提升应用性能
下一篇文章将继续网络类第二轮主题:把日志、缓存、重试、抓包与服务端对齐流程整合成可落地的“问题定位与性能治理”体系,敬请期待!
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- Dio Cache Interceptor官方文档:https://pub.dev/packages/dio_cache_interceptor
- Dio Cache Interceptor GitHub:https://github.com/llfbandit/dio_cache_interceptor
- Dio文档:https://pub.dev/packages/dio
- HTTP缓存:https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching
- Cache-Control:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
- File Store:https://pub.dev/packages/dio_cache_interceptor_file_store
- Hive Store:https://pub.dev/packages/dio_cache_interceptor_hive_store
- 缓存最佳实践:https://web.dev/http-cache/
- 离线优先:https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook
- PWA缓存策略:https://developers.google.com/web/tools/workbox/modules/workbox-strategies
更多推荐

所有评论(0)