如何在WSGI中实现缓存?

2 投票
3 回答
2860 浏览
提问于 2025-04-16 12:31

我想用Python做一个缓存代理,作为WSGI中间件。我在想,这个中间件怎么才能知道缓存的页面是否过期。根据我的了解,WSGI并不支持类似Java Servlets中的getLastModified(HttpServletRequest req)这个方法。

我不想要的是针对每个用户的缓存策略,比如“自从某个时间后有修改”或者“etag”。我想要的是像代理服务器那样,为所有用户缓存内容。所以缓存需要检查WSGI应用程序或者REST资源是否被修改,从而判断缓存是否过期。

 client               cache               wsgi app
 ------               -----               --------
    |   get /some/x     |                    |
    |------------------>| /some/x expired?   |
    |                   |------------------->|
    |                   |                    |
    |                   | update /some/x     |
    |                   | if modified        |
    | return /some/x    |<-------------------|
    |<------------------| 

有没有可能在不绕过WSGI的情况下实现这个功能?

3 个回答

0

你可以试试shelve这个东西。这里有个链接可以了解更多。

如果你想用它来缓存网页,可以把网页的代码存到shelve或者缓存里,然后把这些代码返回给用户。当需要修改页面的时候,可以让wsgi来处理。

1

当你提到“构建”时,其实是指自己配置或开发一个工具。现在有很多HTTP缓存工具可以选择。我建议你看看:

  1. 优化网页传输
  2. 或者 Apache中的mod_cache

使用这些工具,你可以设置超时时间来清除缓存。我想问题在于你的内容有多动态。如果你的内容比较静态,这些工具都应该能满足你的需求。

关于WSGI,这里有一个配置的示例,使用SQUID缓存

3

当然可以。首先,只有你自己知道某个资源是否过期。这个资源可能来自一个文件,或者是数据库中的一篇文章,所以并没有一个通用的方法可以判断“过期与否”。下面是一个简单的例子:

class WSGICache(object):

    def __init__(self, app):
        self.app = app
        self.cache = {}

    def is_expired(self, environ):
        """Determine is the resource the request for already expired?

        """
        # FIXME: check is the resource expired, by looking
        # PATH_INFO, if it is a file, it might be last modified time
        # if it is an object from database, see what is the last modified time
        return False

    def __call__(self, environ, start_response):
        path = environ['PATH_INFO']
        cached = self.cache.get(path)
        # do we have valid cache?
        if self.is_expired(environ) or not cached:
            cached = list(self.app(environ, start_response))
            self.cache[path] = cached
        return cached

不过在实际使用中,我建议你使用一些已经构建好的缓存系统,比如Beaker,我觉得它应该能满足你的需求。我没有测试上面的代码,但像这样的中间件应该能够实现你想要的功能。

撰写回答