自定义缓存策略#
有时,服务器提供的响应在逻辑上可缓存,但缺少使 CacheControl 缓存响应所需的标头。HTTP 缓存规范确实允许缓存系统缓存缺少缓存标头的请求。在这种情况下,缓存系统可以使用启发式方法来确定缓存响应的适当时间。
默认情况下,在 CacheControl 中,必须通过缓存标头明确决定是否缓存。当需要缓存通常不会缓存的响应时,用户可以提供启发式方法来调整响应以使其可缓存。
例如,在针对服务运行测试套件时,缓存所有响应可能有助于加快速度,同时仍然对 API 进行实际调用。
缓存启发式方法#
缓存启发式方法允许通过在考虑缓存响应之前调整响应标头来指定缓存策略。
例如,如果我们想实现一种缓存策略,其中每个请求都应缓存一周,我们可以在 cachecontrol.heuristics.Heuristic 中实现该策略。
import calendar
from cachecontrol.heuristics import BaseHeuristic
from datetime import datetime, timedelta
from email.utils import parsedate, formatdate
class OneWeekHeuristic(BaseHeuristic):
def update_headers(self, response):
date = parsedate(response.headers['date'])
expires = datetime(*date[:6]) + timedelta(weeks=1)
return {
'expires' : formatdate(calendar.timegm(expires.timetuple())),
'cache-control' : 'public',
}
def warning(self, response):
msg = 'Automatically cached! Response is Stale.'
return '110 - "%s"' % msg
当收到响应并且我们正在测试它是否可缓存时,在检查其标头之前应用启发式方法。我们还设置了 警告标头 来传达响应可能过期的原因。原始响应被传递到警告标头中以使用其值。例如,如果响应已过期超过 24 小时,则应使用 警告 113。
为了使用此启发式方法,我们将其传递给我们的 CacheControl 构造函数。
from requests import Session
from cachecontrol import CacheControl
sess = CacheControl(Session(), heuristic=OneWeekHeuristic())
sess.get('http://google.com')
r = sess.get('http://google.com')
assert r.from_cache
谷歌主页专门使用负过期标头和私有缓存控制标头来避免缓存。我们设法解决该方面的问题,并使用我们的启发式方法缓存响应。
最佳实践#
缓存启发式方法仍然是一项新功能,这意味着支持有点基础。可能会有一些最佳实践和常见启发式方法可以满足许多用例的需求。例如,在上述启发式方法中,更改 expires 和 cache-control 标头以使响应可缓存非常重要。
如果您确实找到了有用的最佳实践或创建了有用的启发式方法,请考虑发送拉取请求或打开问题。
过期时间#
CacheControl 捆绑了一个 ExpiresAfter 启发式算法,旨在相对轻松地自动缓存一段时间内的响应。以下是一个示例
import requests
from cachecontrol import CacheControlAdapter
from cachecontrol.heuristics import ExpiresAfter
adapter = CacheControlAdapter(heuristic=ExpiresAfter(days=1))
sess = requests.Session()
sess.mount('http://', adapter)
参数与 datetime.timedelta 对象相同。 ExpiresAfter 将覆盖或添加 Expires 标头,并覆盖或将 Cache-Control 标头设置为 public。
上次修改时间#
CacheControl 捆绑了一个 LastModified 启发式算法,按照 RFC7234 模仿 Firefox 的行为。粗略地说,这将页面的过期时间设置为请求时间戳和上次修改时间戳之间差值的 10%。这将限制在 24 小时内。
import requests
from cachecontrol import CacheControlAdapter
from cachecontrol.heuristics import LastModified
adapter = CacheControlAdapter(heuristic=LastModified())
sess = requests.Session()
sess.mount('http://', adapter)
特定于网站的启发式算法#
如果您有一个特定的域想要对其应用特定的启发式算法,请使用单独的适配器。
import requests
from cachecontrol import CacheControlAdapter
from mypkg import MyHeuristic
sess = requests.Session()
sess.mount(
'http://my.specific-domain.com',
CacheControlAdapter(heuristic=MyHeuristic())
)
通过这种方式,您可以将启发式算法限制在特定网站。
警告!#
缓存很难,虽然 HTTP 在定义新鲜度规则方面做得很好,但应谨慎覆盖这些规则。许多人因过于激进的缓存而感到沮丧,因此在使用更激进的启发式算法之前,请仔细考虑您的用例。