computeFreshnessLifetime()
/**
* Returns the number of milliseconds that the response was fresh for, starting from the served
* date.
*/
private fun computeFreshnessLifetime(): Long {
// A:有max-age
val responseCaching = cacheResponse!!.cacheControl
if (responseCaching.maxAgeSeconds != -1) {
return SECONDS.toMillis(responseCaching.maxAgeSeconds.toLong())
}
//B:有Expires header
val expires = this.expires
if (expires != null) {
val servedMillis = servedDate?.time ?: receivedResponseMillis
val delta = expires.time - servedMillis
return if (delta > 0L) delta else 0L
}
// C:有Last-Modifed header,利用它计算一个启发值
if (lastModified != null && cacheResponse.request.url.query == null) {
// As recommended by the HTTP RFC and implemented in Firefox, the max age of a document
// should be defaulted to 10% of the document's age at the time it was served. Default
// expiration dates aren't used for URIs containing a query.
val servedMillis = servedDate?.time ?: sentRequestMillis
val delta = servedMillis - lastModified!!.time
return if (delta > 0L) delta / 10 else 0L
}
// D:
return 0L
}
这个方法用于计算rfc 7234 4.2.1. Calculating Freshness Lifetime中 定义的Freshness Lifetime。
s-maxage:
这里的cache是private cache,于是OkHttp就直接不处理s-maxage。
B:有Expires header:
当Date header不存在时有如下关系图
Date(如果存在时对应的时刻)
|------------------->|
receivedResponseMillis
此时虽然expires.time - receivedResponseMillis会得出一个相比于Date header存在时,更小的Freshness Lifetime。
|-----------------------------Expires - Date--------------|
|------Expires - receivedResponseMillis------|
显然,response如果在更小的Freshness Lifetime里新鲜,必然在更大的Freshness Lifetime也新鲜,只是会更早的stale罢了。所以这么计算也是有意义的。
C:有Last-Modifed header,利用它计算一个启发值
当Date header不存在时有如下关系图
sentRequestMillis Date(如果存在时对应的时刻)
|------------------->|--------------------->|
receivedResponseMillis
使用sentRequestMillis参与计算会得出一个更小的Freshness Lifetime,根据上一小节的讨论这种更小的值也是有意义的。如果使用receivedResponseMillis 则会得出一个更大的值,这可能导致新鲜度判断不准确,例如:
// 根据rfc 7234中的定义,age此时已经是stale了,但是却被错误的判定为fresh
Date(如果存在时) - lastModified < age < receivedResponseMillis - lastModified
if (lastModified != null && cacheResponse.request.url.query == null) {
//...
}
OkHttp只会缓存GET方法,所以上述代码表示当GET方法不带"?"时,才能使用lastModified计算Freshness Lifetime。这实际是在实现:
Note: Section 13.9 of [RFC2616] prohibited caches from calculating
heuristic freshness for URIs with query components (i.e., those
containing '?'). In practice, this has not been widely
implemented. Therefore, origin servers are encouraged to send
explicit directives (e.g., Cache-Control: no-cache) if they wish
to preclude caching.