首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >改进烧瓶缓存装饰器

改进烧瓶缓存装饰器
EN

Code Review用户
提问于 2016-11-14 22:54:48
回答 1查看 1.9K关注 0票数 8

在我开发烧瓶应用程序的隆隆声中,我找到了缓存装饰器。装饰师是一段简短的、写得很好的代码,但我觉得它忽略了以下几点:

  • 它只缓存在服务器端,而不利用客户端缓存--这意味着每次需要资源时,客户端仍然必须访问服务器。
  • 它不尊重客户端的无缓存要求(虽然我理解为什么一个人可能不想这样做,因为这意味着每次有人请求时都会中断缓存,从而创造了将缓存工作量和效益降低到零的可能性)。

我试图改进它的方法是有一个装饰器,它允许我在每个视图中定义一个缓存控制策略,这个策略同时涉及客户端和服务器端,方法是遵循下面的流程图,该流程图摘自Google Guru Ilya Grigorik的HTTP缓存文章。

装饰师的代码是:

代码语言:javascript
复制
import binascii
import datetime
from flask import Response, make_response
def cached(cacheable = False, must_revalidate = True, client_only = True, client_timeout = 0, server_timeout = 5 * 60, key='view/%s'):
    """

    @see https://jakearchibald.com/2016/caching-best-practices/
        https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
    """
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            cache_key = key % request.full_path # include querystring
            cache_policy = ''
            etag = ''
            if not cacheable:
                cache_policy += ', no-store' # tells the browser not to cache at all
            else:
                if must_revalidate: # this looks contradicting if you haven't read the article.
                    # no-cache doesn't mean "don't cache", it means it must check
                    # (or "revalidate" as it calls it) with the server before
                    # using the cached resource
                    cache_policy += ', no-cache'
                else:
                    # Also must-revalidate doesn't mean "must revalidate", it
                    # means the local resource can be used if it's younger than
                    # the provided max-age, otherwise it must revalidate
                    cache_policy += ', must-revalidate'

                if client_only:
                    cache_policy += ', private'
                else:
                    cache_policy += ', public'

                cache_policy += ', max-age=%d' % (client_timeout)

            headers = {}
            cache_policy = cache_policy.strip(',')
            headers['Cache-Control'] = cache_policy
            now = datetime.datetime.utcnow()

            client_etag = request.headers.get('If-None-Match')

            response = cache.get(cache_key)
            # respect the hard-refresh
            if response is not None and request.headers.get('Cache-Control', '') != 'no-cache':
                headers['X-Cache'] = 'HIT from Server'
                cached_etag = response.headers.get('ETag')
                if client_etag and cached_etag and client_etag == cached_etag:
                    headers['X-Cache'] = 'HIT from Client'
                    headers['X-Last-Modified'] = response.headers.get('X-LastModified')
                    response = make_response('', 304)
            else:
                response = make_response(f(*args, **kwargs))
                if response.status_code == 200 and request.method in ['GET', 'HEAD']:
                    headers['X-Cache'] = 'MISS'
                    # - Added the headers to the response object instead of the
                    # headers dict so they get cached too
                    # - If you can find any faster random algorithm go for it.
                    response.headers.add('ETag', binascii.hexlify(os.urandom(4)))
                    response.headers.add('X-Last-Modified', str(now))
                    cache.set(cache_key, response, timeout=server_timeout)

            response.headers.extend(headers)
            return response
        return decorated_function
    return decorator

然后,装潢师可以使用类似的

代码语言:javascript
复制
@pages.route('/')
@cached(True, must_revalidate=True, client_only=False, client_timeout=120, server_timeout=5*60)
def index():
    """Serve client-side application shell."""
    return render_template('shell.html', model = get_default_model())

请注意,装饰器上的cache是由Werkzeug提供的,在这种情况下它是内存中的,但是它可以是redis、memcached等等,因为Werkzeug缓存为它们提供了一个通用的高级API,同时使底层的实现细节远离开发人员的视线或担忧。

我想听听你对此的反馈,与“标准”装潢师相比,这是否是一个有价值的改进,在那里它可以被改进和简化。

EN

回答 1

Code Review用户

发布于 2023-01-07 02:53:21

关于这方面的反馈意见,这是否是一项有价值的改进

是。这太棒了。

我和你一样担心它是否可以简化。但是遗憾的是,web缓存规则有点复杂。

票数 0
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/147038

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档