You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中Dio Cache Interceptor无法缓存请求的问题求助

问题:Flutter中dio_cache_interceptor缓存始终不生效

我正尝试为Flutter应用添加dio_cache_interceptor,使用的版本如下:

dio: ^5.6.0
dio_cache_interceptor: ^3.5.0

但发起请求时,请求始终发送至Web服务器,缓存似乎从未生效。

已尝试或排查的内容:

  • 响应状态码为200
  • 调整过CacheOptions.keyBuilder,生成的请求缓存键始终一致
  • 响应头信息如下:
    • etag:
    • content-type: application/json;charset=utf-8
    • cache-control: private, max-age=86400, stale-if-error=21600
    • date: Fri, 16 Aug 2024, 09:42:46 GMT
    • content-length: 2332
    • x-aspnet-version: 4.0.30319
      (该API由我维护,可添加自定义响应头)
  • 调整过拦截器顺序(缓存拦截器已放在首位)
  • 已安装http: ^1.2.1包,但未在当前文件中使用
  • 查阅过Dio Cache Interceptor官方文档,但未找到解决方法

已花费一整天排查仍无头绪,希望能得到方向指引。

精简后的代码:

import 'dart:async';
import 'package:dio/dio.dart';
import 'package:dio_cache_interceptor/dio_cache_interceptor.dart';

class WebAPIProvider {
  late final Dio dio;
  late final CacheOptions cacheOptions;

  /// WebAPIProvider Constructor
  WebAPIProvider() {
    // Set cache options
    cacheOptions = CacheOptions(
      store: MemCacheStore(),
      policy: CachePolicy.request,
      hitCacheOnErrorExcept: [403],
      maxStale: const Duration(days: 7),
    );

    // Set base options for every request and add interceptors
    dio = Dio(
      BaseOptions(
        baseUrl: 'https://my.domain.com/webapi/v1',
        connectTimeout: const Duration(seconds: 7),
        receiveTimeout: const Duration(seconds: 4),
        responseType: ResponseType.json,
      ),
    )..interceptors.addAll([
        DioCacheInterceptor(
          options: cacheOptions,
        ),
        InterceptorsWrapper(
          onRequest: onDioRequest,
          onResponse: onDioResponse,
          onError: onDioError,
        ),
      ]);
  }

  /// Fired before every Dio request
  /// 
  /// @Stackoverflow: This adds the accessToken (and other stuff) to the header
  FutureOr<void> onDioRequest(
    RequestOptions options,
    RequestInterceptorHandler handler,
  ) async {
    // Set contentType
    options.headers["contentType"] = "application/json";

    // Set accessToken
    options.headers["accessToken"] = "access-token-here";

    // Continue
    return handler.next(options);
  }

  /// Fired at every response Dio receives
  /// 
  /// @Stackoverflow: Using this for logging the reponse
  FutureOr<void> onDioResponse(
    Response response,
    ResponseInterceptorHandler handler,
  ) async {
    // Some logging here...
        
    // Continue
    return handler.next(response);
  }

  /// Fired at any error during the request
  /// 
  /// @Stackoverflow: Using this for logging the error and resolve with an "empty" dataset
  FutureOr<void> onDioError(
    DioException exception,
    handler,
  ) async {
    // Continue with empty response
    return handler.resolve(Response(
      extra: {"exceptionType": exception.type},
      requestOptions: exception.requestOptions,
    ));
  }

  /// 🌐 Invokes the API [endpoint] with optional [requestHeaders] and [queryParameters].
  /// 
  /// @Stackoverflow: This is the method I'm invoking, i.e. data = api.get('/my/endpoint')
  Future<Response> get(
    String endpoint, [
    Map<String, String>? requestHeaders,
    Map<String, dynamic>? queryParameters,
  ]) async {
    // Send request
    Response<dynamic> response = await dio.get(
      endpoint,
      queryParameters: queryParameters,
      options: Options(
        headers: requestHeaders,
      ),
    );

    // Here I would convert it into a specific type, matching my API

    return response;
  }
}

补充说明:尝试将onDioRequest()改为同步方法(原本因从安全存储读取accessToken设为异步),但响应始终包含extra: {@cache_key@: always-same-key, @fromNetwork@: true}的内容。


解决方向指引
  1. 修复请求选项覆盖缓存配置的问题
    当前全局设置的CacheOptions会被get方法中传入的空Options对象覆盖,导致缓存规则未生效。修改get方法的请求代码,把全局缓存配置合并到请求选项中:

    Response<dynamic> response = await dio.get(
      endpoint,
      queryParameters: queryParameters,
      options: cacheOptions.copyWith(headers: requestHeaders).toOptions(),
    );
    
  2. 强制忽略响应头缓存指令
    响应头中的private指令可能干扰缓存行为,可在全局CacheOptions中添加参数,强制使用自定义的缓存规则:

    cacheOptions = CacheOptions(
      store: MemCacheStore(),
      policy: CachePolicy.request,
      hitCacheOnErrorExcept: [403],
      maxStale: const Duration(days: 7),
      overrideCacheHeaders: true, // 强制忽略响应头的缓存指令
    );
    
  3. 排查自定义拦截器的影响
    暂时移除自定义的InterceptorsWrapper,测试缓存是否生效。如果生效,再逐步恢复onRequest/onResponse/onError方法,排查是否有代码修改了请求/响应参数导致缓存无法正常存储或读取。

  4. 验证缓存存储状态
    在请求后手动调用缓存存储的获取方法,确认缓存是否被写入:

    final cacheKey = cacheOptions.keyBuilder(RequestOptions(path: endpoint, baseUrl: dio.options.baseUrl));
    final cachedResponse = await cacheOptions.store.get(cacheKey);
    print(cachedResponse); // 查看是否有缓存数据
    
  5. 测试持久化缓存存储
    MemCacheStore是内存缓存,应用重启后会丢失,可临时换成HiveCacheStore(需添加依赖dio_cache_interceptor_hive_store)测试,确认是否是存储类型的问题。

内容的提问来源于stack exchange,提问作者Boris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 16:15:19