Flutter网络请求进阶:数据缓存优化与网络状态感知动态适配

在企业级Flutter应用中,“数据缓存的精细化控制”与“网络状态的动态适配”是提升用户体验的关键。普通缓存方案易出现数据一致性问题,而固定的网络请求策略无法适配弱网、断网等复杂网络环境。本文聚焦这两大核心痛点,提供“多级缓存架构”“缓存一致性保障”“网络状态实时感知”“动态请求策略调整”的全链路实战方案,进一步强化Flutter网络交互的稳定性与用户体验。

一、核心设计思路:缓存精准控制与网络自适应

本次方案遵循两大核心设计原则,确保功能实用性与扩展性:

  • 多级缓存与精准控制原则:采用“内存缓存+磁盘缓存”多级架构,区分“永久缓存”“时效缓存”“临时缓存”,支持按接口、按数据类型配置缓存策略,同时通过版本号、时间戳保障缓存与服务端数据一致性。

  • 网络感知与动态适配原则:实时监听网络状态(在线/弱网/断网、Wi-Fi/蜂窝网络),针对不同网络场景动态调整请求策略(如弱网时降低并发、增大超时时间;断网时优先读取缓存;Wi-Fi/蜂窝网络切换时重新验证缓存)。

二、数据缓存进阶:多级架构与一致性保障

传统缓存方案多为单一层级、固定时效,易导致“缓存脏数据”“重复请求”“缓存穿透”等问题。本节实现“内存+磁盘”多级缓存,支持个性化缓存策略配置,同时通过多种机制保障缓存与服务端数据一致性。

1. 基础准备:缓存模型与策略枚举

定义缓存数据模型、缓存策略枚举,明确各策略的适用场景,为后续缓存控制提供基础。


import 'dart:convert';
import 'package:intl/intl.dart';

// 缓存策略枚举
enum CacheStrategy {
  permanent, // 永久缓存(如静态配置、字典数据)
  timeLimited, // 时效缓存(如列表数据,需设置过期时间)
  temporary, // 临时缓存(如单次请求结果,应用重启后失效)
  noCache, // 不缓存(如实时性要求极高的支付、登录接口)
}

// 缓存数据模型
class CacheModel {
  // 缓存数据(JSON字符串)
  final String data;
  // 缓存策略
  final CacheStrategy strategy;
  // 过期时间(仅时效缓存有效,毫秒级时间戳)
  final int? expireTime;
  // 数据版本号(用于一致性校验)
  final String version;
  // 缓存时间(毫秒级时间戳)
  final int cacheTime;

  CacheModel({
    required this.data,
    required this.strategy,
    this.expireTime,
    required this.version,
    required this.cacheTime,
  });

  // 转换为Map(用于磁盘存储)
  Map<String, dynamic> toMap() {
    return {
      'data': data,
      'strategy': strategy.name,
      'expireTime': expireTime,
      'version': version,
      'cacheTime': cacheTime,
    };
  }

  // 从Map解析(用于读取磁盘缓存)
  factory CacheModel.fromMap(Map<String, dynamic> map) {
    return CacheModel(
      data: map['data'] as String,
      strategy: CacheStrategy.values.firstWhere(
        (e) => e.name == map['strategy'],
        orElse: () => CacheStrategy.noCache,
      ),
      expireTime: map['expireTime'] as int?,
      version: map['version'] as String,
      cacheTime: map['cacheTime'] as int,
    );
  }

  // 检查缓存是否有效
  bool get isValid {
    switch (strategy) {
      case CacheStrategy.permanent:
        return true; // 永久有效
      case CacheStrategy.timeLimited:
        final now = DateTime.now().millisecondsSinceEpoch;
        return expireTime != null && now < expireTime!;
      case CacheStrategy.temporary:
        // 临时缓存:应用运行期间有效(此处通过缓存时间是否在当前会话内判断,实际可结合应用生命周期)
        return true;
      case CacheStrategy.noCache:
        return false;
    }
  }
}

2. 实现多级缓存工具类:内存+磁盘

封装缓存工具类,管理内存缓存(LRU策略,限制最大容量)与磁盘缓存(基于Hive实现,高效读写),提供缓存增删改查、策略校验等核心方法。


import 'dart:io';
import 'package:hive/hive.dart';
import 'package:path_provider/path_provider.dart';
import 'cache_model.dart';

// LRU内存缓存(限制最大容量,淘汰最少使用的缓存)
class LruMemoryCache {
  final int maxSize;
  final Map<String, CacheModel> _cache = {};
  final List<String> _keys = []; // 记录访问顺序,尾部为最近访问

  LruMemoryCache({this.maxSize = 50});

  // 获取缓存
  CacheModel? get(String key) {
    final model = _cache[key];
    if (model != null) {
      // 更新访问顺序
      _keys.remove(key);
      _keys.add(key);
    }
    return model;
  }

  // 存入缓存
  void put(String key, CacheModel model) {
    if (_cache.containsKey(key)) {
      _keys.remove(key);
    } else if (_cache.length >= maxSize) {
      // 超过最大容量,淘汰最少使用的缓存(头部元素)
      final removeKey = _keys.removeAt(0);
      _cache.remove(removeKey);
    }
    _cache[key] = model;
    _keys.add(key);
  }

  // 移除缓存
  void remove(String key) {
    _cache.remove(key);
    _keys.remove(key);
  }

  // 清空缓存
  void clear() {
    _cache.clear();
    _keys.clear();
  }
}

// 多级缓存工具类(单例)
class CacheManager {
  static final CacheManager _instance = CacheManager._internal();
  factory CacheManager() => _instance;
  CacheManager._internal();

  // 内存缓存(LRU策略)
  late LruMemoryCache _memoryCache;
  // 磁盘缓存(Hive数据库)
  late Box<Map<String, dynamic>> _diskCache;
  // 缓存版本号(全局统一,用于批量失效缓存)
  String _cacheVersion = '1.0.0';

  // 初始化缓存
  Future<void> init() async {
    _memoryCache = LruMemoryCache(maxSize: 50);
    // 初始化Hive,配置磁盘缓存路径
    final dir = await getApplicationDocumentsDirectory();
    Hive.init(dir.path + '/network_cache');
    _diskCache = await Hive.openBox<Map<String, dynamic>>('network_cache_box');
    return;
  }

  // 更新缓存版本号(批量失效所有缓存)
  void updateCacheVersion(String newVersion) {
    _cacheVersion = newVersion;
    clearAllCache();
  }

  // 生成缓存Key(接口路径+方法+参数+版本号,确保唯一性)
  String generateCacheKey({
    required String path,
    required String method,
    Map<String, dynamic>? params,
    Map<String, dynamic>? data,
  }) {
    final paramsStr = params != null ? json.encode(params) : '';
    final dataStr = data != null ? json.encode(data) : '';
    return '$_cacheVersion|$method|$path|$paramsStr|$dataStr';
  }

  // 存入缓存(根据策略存入内存+磁盘,或仅内存)
  Future<void> saveCache({
    required String key,
    required dynamic data,
    required CacheStrategy strategy,
    int? expireSeconds, // 过期秒数(仅时效缓存有效)
  }) async {
    final dataStr = json.encode(data);
    int? expireTime;
    if (strategy == CacheStrategy.timeLimited && expireSeconds != null) {
      expireTime = DateTime.now().millisecondsSinceEpoch + (expireSeconds * 1000);
    }
    final cacheModel = CacheModel(
      data: dataStr,
      strategy: strategy,
      expireTime: expireTime,
      version: _cacheVersion,
      cacheTime: DateTime.now().millisecondsSinceEpoch,
    );

    // 存入内存缓存
    _memoryCache.put(key, cacheModel);

    // 永久缓存、时效缓存存入磁盘;临时缓存不存入磁盘
    if (strategy == CacheStrategy.permanent || strategy == CacheStrategy.timeLimited) {
      await _diskCache.put(key, cacheModel.toMap());
    }
  }

  // 获取缓存(优先内存,再磁盘,校验有效性)
  Future<dynamic?> getCache(String key) async {
    // 1. 从内存缓存获取
    final memoryCache = _memoryCache.get(key);
    if (memoryCache != null && memoryCache.isValid) {
      return json.decode(memoryCache.data);
    }

    // 2. 从磁盘缓存获取
    final diskCacheMap = _diskCache.get(key);
    if (diskCacheMap != null) {
      final diskCache = CacheModel.fromMap(diskCacheMap);
      if (diskCache.isValid && diskCache.version == _cacheVersion) {
        // 存入内存缓存,提升后续访问速度
        _memoryCache.put(key, diskCache);
        return json.decode(diskCache.data);
      } else {
        // 缓存失效,移除
        await _diskCache.delete(key);
      }
    }

    return null;
  }

  // 移除指定缓存
  Future<void> removeCache(String key) async {
    _memoryCache.remove(key);
    await _diskCache.delete(key);
  }

  // 清空所有缓存
  Future<void> clearAllCache() async {
    _memoryCache.clear();
    await _diskCache.clear();
  }

  // 清空过期缓存(定期调用,如应用启动时)
  Future<void> clearExpiredCache() async {
    final now = DateTime.now().millisecondsSinceEpoch;
    final keys = _diskCache.keys;
    for (final key in keys) {
      final cacheMap = _diskCache.get(key);
      if (cacheMap != null) {
        final cache = CacheModel.fromMap(cacheMap);
        if (!cache.isValid || cache.version != _cacheVersion) {
          await _diskCache.delete(key);
        }
      }
    }
    // 清空内存中失效的缓存
    _memoryCache._cache.removeWhere((key, value) => !value.isValid || value.version != _cacheVersion);
  }
}

3. 实现缓存拦截器:请求自动缓存与读取

通过Dio拦截器整合多级缓存工具,实现请求的自动缓存读取与写入,支持在单个请求中配置个性化缓存策略,无需手动处理缓存逻辑。


import 'dart:convert';
import 'package:dio/dio.dart';
import 'cache_manager.dart';
import 'cache_model.dart';

// 单个请求的缓存配置
class RequestCacheConfig {
  // 缓存策略
  final CacheStrategy strategy;
  // 过期秒数(仅时效缓存有效)
  final int? expireSeconds;
  // 是否强制刷新(忽略缓存,直接请求服务端,请求成功后更新缓存)
  final bool forceRefresh;
  // 缓存key生成器(默认使用CacheManager的generateCacheKey)
  final String Function(RequestOptions options)? keyGenerator;

  RequestCacheConfig({
    this.strategy = CacheStrategy.noCache,
    this.expireSeconds,
    this.forceRefresh = false,
    this.keyGenerator,
  });
}

// 缓存拦截器
class CacheInterceptor extends Interceptor {
  final CacheManager _cacheManager = CacheManager();

  @override
  Future<void> onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    // 1. 获取当前请求的缓存配置
    final cacheConfig = options.extra['cacheConfig'] as RequestCacheConfig? ??
        RequestCacheConfig(strategy: CacheStrategy.noCache);

    // 2. 不缓存或强制刷新,直接放行
    if (cacheConfig.strategy == CacheStrategy.noCache || cacheConfig.forceRefresh) {
      handler.next(options);
      return;
    }

    // 3. 生成缓存key
    final cacheKey = cacheConfig.keyGenerator?.call(options) ??
        _cacheManager.generateCacheKey(
          path: options.path,
          method: options.method,
          params: options.queryParameters,
          data: options.data,
        );

    // 4. 获取缓存
    final cacheData = await _cacheManager.getCache(cacheKey);
    if (cacheData != null) {
      // 有有效缓存,直接返回缓存数据,不发起网络请求
      handler.resolve(
        Response(
          requestOptions: options,
          data: cacheData,
          statusCode: 200,
        ),
      );
      return;
    }

    // 5. 无缓存,继续发起网络请求,并将缓存key存入extra
    options.extra['cacheKey'] = cacheKey;
    options.extra['cacheConfig'] = cacheConfig;
    handler.next(options);
  }

  @override
  Future<void> onResponse(Response response, ResponseInterceptorHandler handler) async {
    // 1. 获取请求的缓存配置和缓存key
    final cacheConfig = response.requestOptions.extra['cacheConfig'] as RequestCacheConfig?;
    final cacheKey = response.requestOptions.extra['cacheKey'] as String?;

    // 2. 无需缓存或无缓存key,直接放行
    if (cacheConfig == null || cacheConfig.strategy == CacheStrategy.noCache || cacheKey == null) {
      handler.next(response);
      return;
    }

    // 3. 存入缓存
    await _cacheManager.saveCache(
      key: cacheKey,
      data: response.data,
      strategy: cacheConfig.strategy,
      expireSeconds: cacheConfig.expireSeconds,
    );

    handler.next(response);
  }

  @override
  Future<void> onError(DioException err, ErrorInterceptorHandler handler) async {
    // 网络请求失败时,尝试返回缓存(仅针对GET请求)
    if (err.requestOptions.method.toUpperCase() == 'GET') {
      final cacheConfig = err.requestOptions.extra['cacheConfig'] as RequestCacheConfig?;
      final cacheKey = err.requestOptions.extra['cacheKey'] as String?;
      if (cacheConfig != null && cacheConfig.strategy != CacheStrategy.noCache && cacheKey != null) {
        final cacheData = await _cacheManager.getCache(cacheKey);
        if (cacheData != null) {
          // 返回缓存数据,避免用户看到错误
          handler.resolve(
            Response(
              requestOptions: err.requestOptions,
              data: cacheData,
              statusCode: 200,
            ),
          );
          return;
        }
      }
    }
    handler.next(err);
  }
}

三、网络状态感知:实时监听与动态适配

通过监听网络状态变化,动态调整请求策略(超时时间、并发数、缓存策略、重试机制),提升弱网/断网场景下的用户体验,同时避免无效请求浪费资源。

1. 基础准备:网络状态模型与监听工具

使用connectivity_plus插件监听网络状态,定义网络状态模型,提供全局网络状态访问与变化回调。


import 'dart:async';
import 'package:connectivity_plus/connectivity_plus.dart';

// 网络类型枚举
enum NetworkType {
  wifi, // Wi-Fi
  mobile, // 蜂窝网络(4G/5G等)
  none, // 无网络
  other, // 其他网络
}

// 网络状态模型
class NetworkState {
  final bool isConnected; // 是否连接网络
  final NetworkType type; // 网络类型

  NetworkState({
    required this.isConnected,
    required this.type,
  });

  // 弱网判断(可根据实际业务调整,如蜂窝网络且信号弱)
  bool get isWeakNetwork => isConnected && type == NetworkType.mobile;
}

// 网络状态监听工具(单例)
class NetworkMonitor {
  static final NetworkMonitor _instance = NetworkMonitor._internal();
  factory NetworkMonitor() => _instance;
  NetworkMonitor._internal();

  final Connectivity _connectivity = Connectivity();
  late StreamSubscription<ConnectivityResult> _subscription;
  final StreamController<NetworkState> _stateController = StreamController<NetworkState>.broadcast();
  late NetworkState _currentState;

  // 初始化网络监听
  Future<void> init() async {
    // 获取初始网络状态
    final result = await _connectivity.checkConnectivity();
    _currentState = _mapToNetworkState(result);
    _stateController.add(_currentState);

    // 监听网络状态变化
    _subscription = _connectivity.onConnectivityChanged.listen((result) {
      _currentState = _mapToNetworkState(result);
      _stateController.add(_currentState);
    });
  }

  // 映射ConnectivityResult到NetworkState
  NetworkState _mapToNetworkState(ConnectivityResult result) {
    switch (result) {
      case ConnectivityResult.wifi:
        return NetworkState(isConnected: true, type: NetworkType.wifi);
      case ConnectivityResult.mobile:
        return NetworkState(isConnected: true, type: NetworkType.mobile);
      case ConnectivityResult.none:
        return NetworkState(isConnected: false, type: NetworkType.none);
      default:
        return NetworkState(isConnected: true, type: NetworkType.other);
    }
  }

  // 获取当前网络状态
  NetworkState get currentState => _currentState;

  // 网络状态变化流(外部可监听)
  Stream<NetworkState> get stateStream => _stateController.stream;

  // 取消监听
  void dispose() {
    _subscription.cancel();
    _stateController.close();
  }
}

2. 实现网络适配拦截器:动态调整请求策略

通过Dio拦截器结合网络监听工具,根据当前网络状态动态调整请求参数(超时时间、并发数、重试策略),实现请求策略的自适应优化。


import 'package:dio/dio.dart';
import 'network_monitor.dart';
import 'retry_interceptor.dart'; // 复用之前的重试配置

// 网络适配配置(不同网络状态的策略)
class NetworkAdaptConfig {
  // Wi-Fi环境配置
  final Duration wifiTimeout;
  final int wifiMaxRetries;
  final int wifiConcurrentCapacity;

  // 蜂窝网络环境配置
  final Duration mobileTimeout;
  final int mobileMaxRetries;
  final int mobileConcurrentCapacity;

  // 无网络环境配置(是否优先读取缓存)
  final bool noneNetworkUseCache;

  NetworkAdaptConfig({
    // Wi-Fi配置
    this.wifiTimeout = const Duration(milliseconds: 15000),
    this.wifiMaxRetries = 3,
    this.wifiConcurrentCapacity = 10,

    // 蜂窝网络配置(弱网优化:更长超时,更少重试,更低并发)
    this.mobileTimeout = const Duration(milliseconds: 30000),
    this.mobileMaxRetries = 2,
    this.mobileConcurrentCapacity = 5,

    // 无网络配置
    this.noneNetworkUseCache = true,
  });
}

// 网络适配拦截器
class NetworkAdaptInterceptor extends Interceptor {
  final NetworkMonitor _networkMonitor = NetworkMonitor();
  final NetworkAdaptConfig _adaptConfig;
  final ConcurrentControlInterceptor _concurrentInterceptor; // 并发控制拦截器实例

  NetworkAdaptInterceptor({
    required NetworkAdaptConfig adaptConfig,
    required ConcurrentControlInterceptor concurrentInterceptor,
  })  : _adaptConfig = adaptConfig,
        _concurrentInterceptor = concurrentInterceptor {
    // 监听网络状态变化,动态调整并发控制速率
    _networkMonitor.stateStream.listen((state) {
      _adjustConcurrentRate(state);
    });
  }

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
    final networkState = _networkMonitor.currentState;

    // 1. 无网络时,强制使用缓存(覆盖请求的缓存配置)
    if (!networkState.isConnected) {
      final originalCacheConfig = options.extra['cacheConfig'] as RequestCacheConfig? ??
          RequestCacheConfig(strategy: CacheStrategy.noCache);
      options.extra['cacheConfig'] = originalCacheConfig.copyWith(
        forceRefresh: false, // 禁止强制刷新
        strategy: originalCacheConfig.strategy == CacheStrategy.noCache
            ? CacheStrategy.temporary // 无缓存策略时,临时启用临时缓存
            : originalCacheConfig.strategy,
      );
    }

    // 2. 动态调整超时时间
    options.connectTimeout = _getTimeoutByNetworkState(networkState);
    options.sendTimeout = options.connectTimeout;
    options.receiveTimeout = options.connectTimeout;

    // 3. 动态调整重试策略
    final originalRetryConfig = options.extra['retryConfig'] as RetryConfig? ??
        const RetryConfig();
    options.extra['retryConfig'] = originalRetryConfig.copyWith(
      maxRetries: _getMaxRetriesByNetworkState(networkState),
    );

    handler.next(options);
  }

  // 根据网络状态获取超时时间
  Duration _getTimeoutByNetworkState(NetworkState state) {
    if (!state.isConnected) {
      return const Duration(milliseconds: 5000); // 无网络时,快速结束请求,优先读缓存
    }
    switch (state.type) {
      case NetworkType.wifi:
        return _adaptConfig.wifiTimeout;
      case NetworkType.mobile:
        return _adaptConfig.mobileTimeout;
      default:
        return _adaptConfig.wifiTimeout;
    }
  }

  // 根据网络状态获取最大重试次数
  int _getMaxRetriesByNetworkState(NetworkState state) {
    if (!state.isConnected) {
      return 0; // 无网络时不重试
    }
    switch (state.type) {
      case NetworkType.wifi:
        return _adaptConfig.wifiMaxRetries;
      case NetworkType.mobile:
        return _adaptConfig.mobileMaxRetries;
      default:
        return _adaptConfig.wifiMaxRetries;
    }
  }

  // 根据网络状态调整并发控制速率
  void _adjustConcurrentRate(NetworkState state) {
    if (!state.isConnected) {
      _concurrentInterceptor.adjustTokenRate(0); // 无网络时,暂停并发请求
      return;
    }
    switch (state.type) {
      case NetworkType.wifi:
        _concurrentInterceptor.adjustTokenRate(_adaptConfig.wifiConcurrentCapacity / 2);
        break;
      case NetworkType.mobile:
        _concurrentInterceptor.adjustTokenRate(_adaptConfig.mobileConcurrentCapacity / 2);
        break;
      default:
        _concurrentInterceptor.adjustTokenRate(_adaptConfig.wifiConcurrentCapacity / 2);
    }
  }
}

3. 整合所有组件:构建自适应网络请求体系

将多级缓存拦截器、网络适配拦截器与之前的加密、并发控制、重试、异常监控拦截器整合,形成完整的“缓存优化+网络自适应”高级网络体系。


import 'package:dio/dio.dart';
import 'cache_interceptor.dart';
import 'network_adapt_interceptor.dart';
import 'concurrent_control_interceptor.dart';
import 'retry_interceptor.dart';
import 'exception_monitor_interceptor.dart';
import 'encrypt_interceptor.dart';
import 'env_manager.dart';
import 'cache_manager.dart';
import 'network_monitor.dart';

class AdaptiveNetworkUtil {
  static final AdaptiveNetworkUtil _instance = AdaptiveNetworkUtil._internal();
  factory AdaptiveNetworkUtil() => _instance;
  late Dio _dio;
  late EnvManager _envManager;
  late CacheManager _cacheManager;
  late NetworkMonitor _networkMonitor;
  late ConcurrentControlInterceptor _concurrentInterceptor;

  AdaptiveNetworkUtil._internal() {
    _envManager = EnvManager();
    _cacheManager = CacheManager();
    _networkMonitor = NetworkMonitor();
    _concurrentInterceptor = ConcurrentControlInterceptor(defaultEnableLimit: true);
    // 初始化核心组件
    _initCoreComponents();
  }

  // 初始化核心组件(缓存、网络监听、环境配置)
  Future<void> _initCoreComponents() async {
    await _envManager.init();
    await _cacheManager.init();
    await _cacheManager.clearExpiredCache(); // 清除过期缓存
    await _networkMonitor.init();
    _initDio();
  }

  // 初始化Dio(整合所有拦截器)
  void _initDio() {
    _dio = Dio();
    final envConfig = _envManager.currentConfig;

    // 1. 异常监控拦截器(最先添加,捕获所有异常)
    _dio.interceptors.add(ExceptionMonitorInterceptor(
      config: ExceptionMonitorConfig(
        enableLocalLog: envConfig.enableLog,
        enableRemoteReport: true,
        reportLevelThreshold: ExceptionLevel.warning,
        onReport: (exception) async {
          await _dio.post(
            envConfig.exceptionReportUrl,
            data: exception.toJson(),
            options: Options(extra: {
              'concurrentControl': ConcurrentControlConfig(skipLimit: true),
              'cacheConfig': RequestCacheConfig(strategy: CacheStrategy.noCache),
            }),
          );
        },
      ),
    ));

    // 2. 缓存拦截器(第二添加,优先读取缓存)
    _dio.interceptors.add(CacheInterceptor());

    // 3. 网络适配拦截器(调整请求策略)
    _dio.interceptors.add(NetworkAdaptInterceptor(
      adaptConfig: NetworkAdaptConfig(
        // Wi-Fi配置
        wifiTimeout: const Duration(milliseconds: 15000),
        wifiMaxRetries: 3,
        wifiConcurrentCapacity: 10,
        // 蜂窝网络配置
        mobileTimeout: const Duration(milliseconds: 30000),
        mobileMaxRetries: 2,
        mobileConcurrentCapacity: 5,
        // 无网络配置
        noneNetworkUseCache: true,
      ),
      concurrentInterceptor: _concurrentInterceptor,
    ));

    // 4. 并发控制拦截器
    _dio.interceptors.add(_concurrentInterceptor);

    // 5. 加密拦截器
    _dio.interceptors.add(EncryptInterceptor(
      config: EncryptInterceptorConfig(
        enableEncrypt: envConfig.enableEncrypt,
        signSecret: envConfig.signSecret,
        skipEncryptPaths: envConfig.skipEncryptPaths,
      ),
    ));

    // 6. 重试拦截器(最后添加,捕获前面拦截器的异常并重试)
    _dio.interceptors.add(RetryInterceptor(
      defaultRetryConfig: const RetryConfig(),
    ));

    // 基础配置
    _dio.options.baseUrl = envConfig.baseUrl;
    _dio.options.connectTimeout = const Duration(milliseconds: 15000);
  }

  // 对外提供请求方法(支持缓存、并发、重试等配置)
  Future<T?> request<T>(
    String path, {
    required String method,
    Map<String, dynamic>? queryParams,
    dynamic data,
    Options? options,
    RequestCacheConfig? cacheConfig,
    ConcurrentControlConfig? concurrentControl,
    RetryConfig? retryConfig,
    bool skipEncrypt = false,
  }) async {
    final extra = <String, dynamic>{};
    if (cacheConfig != null) extra['cacheConfig'] = cacheConfig;
    if (concurrentControl != null) extra['concurrentControl'] = concurrentControl;
    if (retryConfig != null) extra['retryConfig'] = retryConfig;
    if (skipEncrypt) extra['skipEncrypt'] = true;

    final requestOptions = Options(
      method: method,
      ...options,
      extra: {
        ...options?.extra ?? {},
        ...extra,
      },
    );

    try {
      final response = await _dio.request(
        path,
        queryParameters: queryParams,
        data: data,
        options: requestOptions,
      );
      return response.data as T?;
    } catch (e) {
      if (envConfig.enableLog) {
        print('请求失败:$e');
      }
      rethrow;
    }
  }

  // 封装GET请求(默认启用时效缓存,过期时间30秒)
  Future<T?> get<T>(
    String path, {
    Map<String, dynamic>? queryParams,
    Options? options,
    RequestCacheConfig? cacheConfig = const RequestCacheConfig(
      strategy: CacheStrategy.timeLimited,
      expireSeconds: 30,
    ),
    ConcurrentControlConfig? concurrentControl,
    RetryConfig? retryConfig,
    bool skipEncrypt = false,
  }) =>
      request<T>(
        path,
        method: 'GET',
        queryParams: queryParams,
        options: options,
        cacheConfig: cacheConfig,
        concurrentControl: concurrentControl,
        retryConfig: retryConfig,
        skipEncrypt: skipEncrypt,
      );

  // 封装POST请求(默认不缓存)
  Future<T?> post<T>(
    String path, {
    dynamic data,
    Map<String, dynamic>? queryParams,
    Options? options,
    RequestCacheConfig? cacheConfig = const RequestCacheConfig(strategy: CacheStrategy.noCache),
    ConcurrentControlConfig? concurrentControl,
    RetryConfig? retryConfig,
    bool skipEncrypt = false,
  }) =>
      request<T>(
        path,
        method: 'POST',
        data: data,
        queryParams: queryParams,
        options: options,
        cacheConfig: cacheConfig,
        concurrentControl: concurrentControl,
        retryConfig: retryConfig,
        skipEncrypt: skipEncrypt,
      );

  // 对外提供缓存操作方法
  Future<void> clearAllCache() => _cacheManager.clearAllCache();
  Future<void> updateCacheVersion(String newVersion) => _cacheManager.updateCacheVersion(newVersion);

  // 对外提供网络状态访问
  NetworkState get currentNetworkState => _networkMonitor.currentState;
  Stream<NetworkState> get networkStateStream => _networkMonitor.stateStream;
}

final adaptiveNetUtil = AdaptiveNetworkUtil();

四、实战场景:典型业务场景的配置示例

针对不同业务场景,给出个性化的网络请求配置示例,帮助开发者快速落地。

1. 场景1:首页列表数据(弱网优先缓存,Wi-Fi自动刷新)


// 监听网络状态,Wi-Fi时强制刷新,弱网/断网时读取缓存
Future<void> loadHomeList() async {
  final networkState = adaptiveNetUtil.currentNetworkState;
  try {
    final listData = await adaptiveNetUtil.get<List<dynamic>>(
      '/api/home/list',
      cacheConfig: RequestCacheConfig(
        strategy: CacheStrategy.timeLimited,
        expireSeconds: 60, // 缓存1分钟
        forceRefresh: networkState.type == NetworkType.wifi, // Wi-Fi时强制刷新
      ),
      retryConfig: RetryConfig(
        maxRetries: networkState.isWeakNetwork ? 1 : 3, // 弱网时减少重试
      ),
    );
    // 渲染列表
  } catch (e) {
    // 异常处理(无网络时已优先返回缓存,此处仅处理缓存不存在的情况)
    print('加载首页列表失败:$e');
  }
}

2. 场景2:静态配置数据(永久缓存,版本更新时失效)


// 加载静态配置(如地区列表、字典数据)
Future<void> loadStaticConfig() async {
  try {
    final configData = await adaptiveNetUtil.get<Map<String, dynamic>>(
      '/api/config/static',
      cacheConfig: RequestCacheConfig(
        strategy: CacheStrategy.permanent, // 永久缓存
      ),
    );
    // 使用配置数据
  } catch (e) {
    print('加载静态配置失败:$e');
  }
}

// 应用版本更新时,更新缓存版本号,批量失效永久缓存
void onAppVersionUpdated(String newAppVersion) {
  adaptiveNetUtil.updateCacheVersion(newAppVersion);
}

3. 场景3:实时支付接口(不缓存,弱网增大超时)


// 支付请求(实时性极高,不缓存,弱网时增大超时)
Future<void> submitPayment(Map<String, dynamic> paymentData) async {
  final networkState = adaptiveNetUtil.currentNetworkState;
  try {
    final result = await adaptiveNetUtil.post<Map<String, dynamic>>(
      '/api/payment/submit',
      data: paymentData,
      cacheConfig: RequestCacheConfig(strategy: CacheStrategy.noCache), // 不缓存
      retryConfig: RetryConfig(enableRetry: false), // 不重试(避免重复支付)
      options: Options(
        sendTimeout: networkState.isWeakNetwork
            ? const Duration(milliseconds: 60000) // 弱网时超时60秒
            : const Duration(milliseconds: 30000),
      ),
    );
    // 处理支付结果
  } catch (e) {
    print('支付请求失败:$e');
    // 提示用户检查网络或重试
  }
}

五、结语:构建自适应、高可用的网络交互层

本文提出的“多级缓存优化+网络状态感知动态适配”方案,聚焦数据一致性与复杂网络环境适配两大核心痛点,与此前的“加密、并发控制、异常监控、多环境适配、断点续传”共同构成了覆盖全场景的Flutter高级网络体系。通过精细化的缓存策略配置、实时的网络状态监听与动态的请求参数调整,能够有效提升应用在弱网、断网等极端场景下的可用性,同时减少无效网络请求,降低服务端压力。

实际开发中,需结合业务特性灵活调整配置:例如内容类应用可强化缓存策略,提升离线阅读体验;金融类应用需严格控制缓存范围,确保交易数据的实时性与安全性;社交类应用可优化弱网下的重试与并发策略,提升消息收发的稳定性。通过本文的实战方案,开发者可快速搭建自适应、高可用的网络交互层,为用户提供流畅、稳定的网络体验,同时降低后期维护成本。

欢迎大家加入开源鸿蒙跨平台开发者社区,一起共建开源鸿蒙跨平台生态。

Logo

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

更多推荐