dio_cache_interceptor缓存拦截器框架:CacheStrategy、CacheStrategyFactory源码(五)
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()
方法,用于计算要使用的缓存策略。以下是该方法的主要逻辑:
-
解析请求中的缓存控制标头,获取请求的缓存控制信息。
-
如果有网络响应且缓存响应为空,则根据一些条件判断是否可以缓存响应,并创建一个新的缓存响应。
-
如果已经有缓存响应,则根据缓存策略和缓存响应的状态进行相应的处理。
- 如果缓存策略为
forceCache
,直接返回缓存响应。 - 如果缓存未过期,直接返回缓存响应。
- 如果缓存已过期,根据缓存响应的条件(ETag、Last-Modified)设置请求头用于验证。
- 如果缓存策略为
-
如果以上条件均不满足,返回一个缓存策略,其中包含原始请求对象。
这个方法根据请求、响应和缓存的状态计算出应该采取的缓存策略,以便在网络请求时能够根据具体情况使用缓存或重新请求。
_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
方法,用于判断是否可以将给定的响应存储以便稍后用于另一个请求。以下是该方法的主要逻辑:
- 如果缓存策略为
noCache
,则不可缓存,直接返回false
。 - 获取响应的状态码,如果状态码不存在,则不可缓存,返回
false
。 - 如果响应标记为附件下载,则不可缓存,返回
false
。 - 解析响应的缓存控制标头,获取响应的缓存控制信息。
- 如果请求或响应的缓存控制标头中包含
noStore
,并且不强制缓存响应,则不可缓存,返回false
。 - 检查响应的状态码是否在允许缓存的状态码列表中,如果不在列表中,则特殊处理 302 和 307 状态码,确保响应满足缓存条件。
- 最终,调用
_hasCacheDirectives
方法检查响应是否包含适当的缓存指令,以确定是否可缓存。
该方法通过考虑请求、响应的缓存控制信息和状态码,以及一些其他因素,判断响应是否适合进行缓存。
_enforceResponseCachable
bool _enforceResponseCachable() {
final policy = cacheOptions.policy;
return policy == CachePolicy.forceCache ||
policy == CachePolicy.refreshForceCache;
}
_enforceResponseCachable
方法用于判断是否需要强制缓存响应,即根据缓存策略来判断是否要求缓存响应。以下是该方法的逻辑:
- 获取缓存策略。
- 如果缓存策略是
forceCache
或者refreshForceCache
,则需要强制缓存响应,返回true
。 - 否则,不需要强制缓存响应,返回
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
方法用于检查响应是否包含与缓存相关的指令,以判断是否可以将该响应缓存起来。以下是该方法的逻辑:
-
如果
_enforceResponseCachable()
方法返回true
,意味着需要强制缓存响应,那么直接返回true
。 -
否则,检查以下条件:
- 响应的头部中是否包含
ETag
标志。 - 响应的头部中是否包含
Last-Modified
标志。 - 响应的头部中是否包含
Expires
标志。 - 响应的缓存控制中是否设置了
maxAge
大于 0。
- 响应的头部中是否包含
-
如果任何一个条件为真,返回
true
,表示响应包含与缓存相关的指令,可以缓存。 -
如果以上条件都为假,返回
false
,表示响应不包含与缓存相关的指令,不适合缓存。
这个方法用于检查响应头部是否包含了缓存相关的信息,从而决定是否可以将响应缓存起来。
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgiiefi
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13