欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

前言

在移动应用开发中,网络请求往往是耗电且耗时的。为了提升用户体验(如离线访问、秒开页面)和减少服务器负载,HTTP 缓存机制至关重要。

dio 是 Flutter 最流行的网络库,而 dio_cache_interceptor 是基于它的强大插件,提供了符合 HTTP 标准(RFC 7234)的缓存策略。本文将带你一步步在 OpenHarmony 项目中集成它,打造高性能的网络层。

一、核心特性与适配

1.1 核心功能

  • 多存储后端:支持内存 (MemStore)、文件 (FileStore)、数据库 (DbStore/HiveStore) 等。
  • 策略灵活:支持 CachePolicy.forceCache, refresh, noCache 等多种模式。
  • 标准兼容:自动处理 ETag, Last-Modified, Cache-Control 等头信息。

1.2 OpenHarmony 适配说明

该库主要依赖 Dart 的 IO 和存储能力。在 OpenHarmony 上:

  • MemStore: 直接可用。
  • FileStore/DbStore: 需配合 path_provider 获取应用沙箱路径。
  • HiveStore: 需确保 hive 已适配(通常纯 Dart 版没问题)。

本教程推荐使用 MemCacheStore(测试用)或 FileCacheStore(持久化)。

发起请求

拦截器

命中且有效

未命中或过期

响应数据

用户应用

Dio

检查缓存

返回缓存响应

发起网络请求

更新缓存存储

返回网络响应

二、集成与配置

2.1 添加依赖

dependencies:
  dio: ^5.0.0
  dio_cache_interceptor: ^3.5.0
  # 鸿蒙适配版本 (示例)
  path_provider:
    git:
      url: https://gitee.com/openharmony-sig/flutter_packages.git
      path: packages/path_provider/path_provider

2.2 基础配置

初始化 Dio 并添加拦截器。

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'; // 需额外引入 store 库

// 全局缓存选项配置
final options = CacheOptions(
  store: MemCacheStore(), // 内存存储,重启即失
  policy: CachePolicy.request, // 默认策略:有缓存读缓存,过期则请求
  hitCacheOnErrorExcept: [401, 403], // 遇到特定错误时也尝试返回缓存
  maxStale: const Duration(days: 7), // 最大过期时间
  priority: CachePriority.normal, // 缓存优先级
  cipher: null, // 可选加密
  keyBuilder: CacheOptions.defaultCacheKeyBuilder,
  allowPostMethod: false, // 默认不缓存 POST
);

final dio = Dio()..interceptors.add(DioCacheInterceptor(options: options));

三、缓存策略详解与示例

3.1 示例一:基础 GET 请求缓存

最简单的用法,利用默认配置发起 GET 请求。

Future<void> fetchUserData() async {
  try {
    // 第一次请求:从网络获取并缓存
    var response = await dio.get('https://api.example.com/user/1');
    print('First call: ${response.statusCode}, Source: ${response.extra}');

    // 第二次请求(如果未过期):直接返回缓存
    response = await dio.get('https://api.example.com/user/1');
    print('Second call: ${response.statusCode}, Source: ${response.extra}'); 
  } catch (e) {
    print('Failed: $e');
  }
}

在这里插入图片描述

3.2 示例二:强制刷新与强制缓存

有时我们需要手动控制缓存行为。

// 强制刷新:忽略本地缓存,从网络拉取并更新缓存
dio.get(
  'url',
  options: options.copyWith(policy: CachePolicy.refresh).toOptions(),
);

// 强制缓存:无论是否过期,只要有缓存就用(常用于离线模式)
dio.get(
  'url',
  options: options.copyWith(policy: CachePolicy.forceCache).toOptions(),
);

在这里插入图片描述

3.3 示例三:持久化缓存(OpenHarmony 适配)

使用文件系统存储缓存,即使 App 重启也能生效。需要 path_provider

import 'package:path_provider/path_provider.dart';
import 'package:dio_cache_interceptor_file_store/dio_cache_interceptor_file_store.dart';

Future<CacheStore> getFileStore() async {
  final dir = await getApplicationDocumentsDirectory();
  // 在 OpenHarmony 沙箱目录下创建缓存文件夹
  return FileCacheStore('${dir.path}/http_cache');
}

在这里插入图片描述

四、完整实战示例:离线新闻列表

本示例展示一个简单的新闻列表页。即使断网,用户也能看到上次加载的数据。

4.1 核心逻辑

import 'package:flutter/material.dart';
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';
// 注意:实际项目中通常需要单独引入 store 库,这里假设使用内存或已定义的文件 store
// import 'package:dio_cache_interceptor_store_file/dio_cache_interceptor_store_file.dart';

void main() {
  runApp(const MaterialApp(home: NewsPage()));
}

class NewsPage extends StatefulWidget {
  const NewsPage({super.key});

  
  State<NewsPage> createState() => _NewsPageState();
}

class _NewsPageState extends State<NewsPage> {
  late Dio _dio;
  String _content = "暂无数据";
  bool _loading = false;

  
  void initState() {
    super.initState();
    _initDio();
  }

  void _initDio() {
    // 简单起见使用内存存储
    final options = CacheOptions(
      store: MemCacheStore(), 
      policy: CachePolicy.forceCache, // 优先读缓存
      hitCacheOnErrorExcept: [], 
      maxStale: const Duration(days: 1),
    );

    _dio = Dio()..interceptors.add(DioCacheInterceptor(options: options));
  }

  Future<void> _loadNews({bool forceRefresh = false}) async {
    setState(() {
      _loading = true;
      _content = "加载中...";
    });

    try {
      final cacheOptions = CacheOptions(
        store: MemCacheStore(), // 注意:这里创建新的 store 实例仅作演示,实际应复用
        policy: forceRefresh ? CachePolicy.refresh : CachePolicy.forceCache,
      );

      // 模拟请求一个公共 API
      final response = await _dio.get(
        'https://jsonplaceholder.typicode.com/posts/1',
        options: forceRefresh 
            ? Options(extra: cacheOptions.toExtra()) // 覆盖默认策略
            : null,
      );

      final isFromCache = response.extra[CacheResponse.fromNetwork] == false;
      
      setState(() {
        _content = "标题: ${response.data['title']}\n"
                   "来源: ${isFromCache ? '📦 本地缓存' : '🌐 网络请求'}";
      });
    } catch (e) {
      setState(() => _content = "错误: $e");
    } finally {
      setState(() => _loading = false);
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('离线新闻 Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Container(
              padding: const EdgeInsets.all(16),
              margin: const EdgeInsets.all(16),
              color: Colors.grey[200],
              child: Text(
                _content, 
                style: const TextStyle(fontSize: 18),
                textAlign: TextAlign.center,
              ),
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton.icon(
                  icon: const Icon(Icons.download),
                  label: const Text('加载 (优先缓存)'),
                  onPressed: () => _loadNews(forceRefresh: false),
                ),
                const SizedBox(width: 20),
                ElevatedButton.icon(
                  icon: const Icon(Icons.refresh),
                  label: const Text('刷新 (强制网络)'),
                  onPressed: () => _loadNews(forceRefresh: true),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

在这里插入图片描述

五、总结

dio_cache_interceptor 是 Flutter 生态中最成熟的 HTTP 缓存方案之一。配合 OpenHarmony 的文件系统,它能极大地提升应用的响应速度和离线可用性。

最佳实践

  1. 策略选择:对于实时性要求高的数据(如股价),使用 refresh;对于内容类(如文章),使用 cacheFirstforceCache
  2. 清理过期缓存:虽然库会自动管理,但建议在设置页提供“清除缓存”的功能,通过 cacheStore.clean() 释放空间。
  3. OpenHarmony 路径:确保持久化存储路径正确,避免权限问题。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐