• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

dio_cache_interceptor缓存拦截器框架:CacheStrategy、CacheStrategyFactory源码(五)

武飞扬头像
Nicholas68
帮助1

CacheStrategy

class CacheStrategy {
  final RequestOptions? request;
  final CacheResponse? cacheResponse;

  const CacheStrategy(this.request, this.cacheResponse);
}

这段代码定义了一个 CacheStrategy 类,用于封装请求和缓存响应的策略。该类包含以下字段和构造函数:

  • request: 一个可选的 RequestOptions 对象,表示请求的选项和配置。
  • cacheResponse: 一个可选的 CacheResponse 对象,表示从缓存中获取的响应。

CacheStrategyFactory

class CacheStrategyFactory {
  final RequestOptions request;
  final Response? response;
  CacheResponse? cacheResponse;
  final CacheOptions cacheOptions;

  static const allowedStatusCodes = [
    // OK
    200,
    // Non-Authoritative Information
    203,
    // Moved Permanently
    301,
    // No-Content
    304,
    // Found
    302,
    // Temporary Redirect
    307,
    // Not found
    404,
    // Bad method
    405,
    // Not implemented
    501,
  ];

  CacheStrategyFactory({
    required this.request,
    required this.cacheOptions,
    this.response,
    this.cacheResponse,
  });
  }

这段代码定义了一个 CacheStrategyFactory 类,用于创建缓存策略。该类包含以下字段和构造函数:

  • request: RequestOptions 对象,表示请求的选项和配置。
  • response: 可选的 Response 对象,表示从网络获取的响应。
  • cacheResponse: 可选的 CacheResponse 对象,表示从缓存中获取的响应。
  • cacheOptions: CacheOptions 对象,表示缓存的选项和配置。

静态字段:

  • allowedStatusCodes: 一个包含一些允许缓存的HTTP状态码的列表。

通过创建 CacheStrategyFactory 实例,可以根据请求、响应和缓存配置来创建相应的缓存策略。该工厂类的设计可以根据不同的情况灵活地创建缓存策略,以满足不同的需求。

compute

/// Returns a strategy to use assuming the request can use the network.
Future<CacheStrategy> compute() async {
  final rqCacheCtrl = CacheControl.fromHeader(
    request.headerValuesAsList(cacheControlHeader),
  );

  // Build cache reponse
  final resp = response;
  if (resp != null && cacheResponse == null) {
    if (_enforceResponseCachable() || _isCacheable(rqCacheCtrl, resp)) {
      cacheResponse = await CacheResponse.fromResponse(
        key: cacheOptions.keyBuilder(request),
        options: cacheOptions,
        response: resp,
      );

      return CacheStrategy(null, cacheResponse);
    }
  }

  final cache = cacheResponse;
  if (cache != null) {
    // We have a cached reponse

    // Regardless cache response data, return it.
    if (cacheOptions.policy == CachePolicy.forceCache) {
      return CacheStrategy(null, cache);
    }

    // Check cached response freshness
    final respCtrl = cache.cacheControl;
    if (!respCtrl.noCache && !cache.isExpired(rqCacheCtrl)) {
      return CacheStrategy(null, cache);
    }

    // Find conditions to add to the request for validation.
    if (cache.eTag != null) {
      request.headers[ifNoneMatchHeader] = cache.eTag;
    } else if (cache.lastModified != null) {
      request.headers[ifModifiedSinceHeader] = cache.lastModified;
    } else if (cache.date != null) {
      request.headers[ifModifiedSinceHeader] = HttpDate.format(cache.date!);
    }
  }

  return CacheStrategy(request, null);
}

这段代码实现了 CacheStrategyFactory 中的 compute() 方法,用于计算要使用的缓存策略。以下是该方法的主要逻辑:

  1. 解析请求中的缓存控制标头,获取请求的缓存控制信息。

  2. 如果有网络响应且缓存响应为空,则根据一些条件判断是否可以缓存响应,并创建一个新的缓存响应。

  3. 如果已经有缓存响应,则根据缓存策略和缓存响应的状态进行相应的处理。

    • 如果缓存策略为 forceCache,直接返回缓存响应。
    • 如果缓存未过期,直接返回缓存响应。
    • 如果缓存已过期,根据缓存响应的条件(ETag、Last-Modified)设置请求头用于验证。
  4. 如果以上条件均不满足,返回一个缓存策略,其中包含原始请求对象。

这个方法根据请求、响应和缓存的状态计算出应该采取的缓存策略,以便在网络请求时能够根据具体情况使用缓存或重新请求。

_isCacheable

/// Returns true if [response] can be stored to later serve another request.
bool _isCacheable(CacheControl rqCacheCtrl, Response response) {
  if (cacheOptions.policy == CachePolicy.noCache) return false;

  // Always go to network for uncacheable response codes
  final statusCode = response.statusCode;
  if (statusCode == null) return false;

  // Skip download
  if (response.isAttachment()) return false;

  final respCacheCtrl = CacheControl.fromHeader(
    response.headers[cacheControlHeader],
  );

  // revise no-store header with force policy options
  if ((rqCacheCtrl.noStore || respCacheCtrl.noStore) &&
      !_enforceResponseCachable()) return false;

  if (!allowedStatusCodes.contains(statusCode)) {
    if (statusCode == 302 || statusCode == 307) {
      // 302 & 307 can only be cached with the right response headers.
      // https://datatracker.ietf.org/doc/html/rfc7234#section-3
      if (response.headers[expiresHeader]?.first == null &&
          respCacheCtrl.maxAge == -1 &&
          respCacheCtrl.privacy != null) {
        return false;
      }
    }
  }

  return _hasCacheDirectives(response, respCacheCtrl);
}

这段代码实现了 _isCacheable 方法,用于判断是否可以将给定的响应存储以便稍后用于另一个请求。以下是该方法的主要逻辑:

  1. 如果缓存策略为 noCache,则不可缓存,直接返回 false
  2. 获取响应的状态码,如果状态码不存在,则不可缓存,返回 false
  3. 如果响应标记为附件下载,则不可缓存,返回 false
  4. 解析响应的缓存控制标头,获取响应的缓存控制信息。
  5. 如果请求或响应的缓存控制标头中包含 noStore,并且不强制缓存响应,则不可缓存,返回 false
  6. 检查响应的状态码是否在允许缓存的状态码列表中,如果不在列表中,则特殊处理 302 和 307 状态码,确保响应满足缓存条件。
  7. 最终,调用 _hasCacheDirectives 方法检查响应是否包含适当的缓存指令,以确定是否可缓存。

该方法通过考虑请求、响应的缓存控制信息和状态码,以及一些其他因素,判断响应是否适合进行缓存。

_enforceResponseCachable

bool _enforceResponseCachable() {
  final policy = cacheOptions.policy;

  return policy == CachePolicy.forceCache ||
      policy == CachePolicy.refreshForceCache;
}

_enforceResponseCachable 方法用于判断是否需要强制缓存响应,即根据缓存策略来判断是否要求缓存响应。以下是该方法的逻辑:

  1. 获取缓存策略。
  2. 如果缓存策略是 forceCache 或者 refreshForceCache,则需要强制缓存响应,返回 true
  3. 否则,不需要强制缓存响应,返回 false

这个方法主要用于判断是否在特定缓存策略下需要强制缓存响应。

_hasCacheDirectives

bool _hasCacheDirectives(Response response, CacheControl respCacheCtrl) {
  if (_enforceResponseCachable()) {
    return true;
  }

  var result = response.headers[etagHeader] != null;
  result |= response.headers[lastModifiedHeader] != null;
  result |= response.headers[expiresHeader] != null;
  result |= respCacheCtrl.maxAge > 0;

  return result;
}

_hasCacheDirectives 方法用于检查响应是否包含与缓存相关的指令,以判断是否可以将该响应缓存起来。以下是该方法的逻辑:

  1. 如果 _enforceResponseCachable() 方法返回 true,意味着需要强制缓存响应,那么直接返回 true

  2. 否则,检查以下条件:

    • 响应的头部中是否包含 ETag 标志。
    • 响应的头部中是否包含 Last-Modified 标志。
    • 响应的头部中是否包含 Expires 标志。
    • 响应的缓存控制中是否设置了 maxAge 大于 0。
  3. 如果任何一个条件为真,返回 true,表示响应包含与缓存相关的指令,可以缓存。

  4. 如果以上条件都为假,返回 false,表示响应不包含与缓存相关的指令,不适合缓存。

这个方法用于检查响应头部是否包含了缓存相关的信息,从而决定是否可以将响应缓存起来。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhgiiefi
系列文章
更多 icon
同类精品
更多 icon
继续加载