Skip to content

Instantly share code, notes, and snippets.

@cloverstd cloverstd/cache.py
Last active Apr 16, 2019

Embed
What would you like to do?
tornado cache
# coding: utf-8
try:
import cPickle as pickle
except ImportError:
import pickle
try:
import hashlib
sha1 = hashlib.sha1
except ImportError:
import sha
sha1 = sha.new
import functools
def cache(expires=7200):
def _func(func):
@functools.wraps(func)
def wrapper(handler, *args, **kwargs):
handler.expires = expires
return func(handler, *args, **kwargs)
return wrapper
return _func
class CacheMixin(object):
@property
def cache(self):
return self.application.cache
def prepare(self):
super(CacheMixin, self).prepare()
key = self._generate_key(self.request)
print key
if self.cache.exists(self._prefix(key)):
rv = pickle.loads(self.cache.get(self._prefix(key)))
self.write_cache(rv)
self.finish()
def _generate_key(self, request):
key = pickle.dumps((request.path, request.arguments))
return sha1(key).hexdigest()
def _prefix(self, key):
return "Cache:%s" % key
def write_cache(self, chunk):
super(CacheMixin, self).write(chunk)
def write(self, chunk):
pickled = pickle.dumps(chunk)
key = self._generate_key(self.request)
if hasattr(self, "expires"):
self.cache.set(self._prefix(key), pickled, self.expires)
else:
self.cache.set(self._prefix(key), pickled)
super(CacheMixin, self).write(chunk)
class CacheBackend(object):
"""
The base Cache Backend class
"""
def get(self, key):
raise NotImplementedError
def set(self, key, value, timeout):
raise NotImplementedError
def delitem(self, key):
raise NotImplementedError
def exists(self, key):
raise NotImplementedError
class RedisCacheBackend(CacheBackend):
def __init__(self, redis_connection, **options):
self.options = dict(timeout=86400)
self.options.update(options)
self.redis = redis_connection
def get(self, key):
if self.exists(key):
return self.redis.get(key)
return None
def set(self, key, value, timeout=None):
self.redis.set(key, value)
if timeout:
self.redis.expire(key, timeout)
else:
self.redis.expire(key, self.options["timeout"])
def delitem(self, key):
self.redis.delete(key)
def exists(self, key):
print key
return bool(self.redis.exists(key))
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tornado.web
import tornado.ioloop
from cache import RedisCacheBackend, CacheMixin
import redis
class CacheHandler(CacheMixin, tornado.web.RequestHandler):
def get(self):
self.expires = 60 # set the cache expires
self.write("test")
class Application(tornado.web.Application):
def __init__(self):
settings = dict(debug=True)
self.redis = redis.Redis()
self.cache = RedisCacheBackend(self.redis)
handlers = [(r'/', CacheHandler)]
super(Application, self).__init__(handlers=handlers, **settings)
if __name__ == '__main__':
application = Application()
application.listen(8080)
tornado.ioloop.IOLoop.instance().start()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import tornado.web
import tornado.ioloop
from cache import RedisCacheBackend, CacheMixin, cache
import redis
class BaseHandler(CacheMixin, RequestHandler):
def prepare(self):
super(BaseHandler, self).prepare()
class Greetandler(Cornado.web.RequestHandler):
@cache(60) # set the cache expires
def get(self):
self.write("test")
class Application(tornado.web.Application):
def __init__(self):
settings = dict(debug=True)
self.redis = redis.Redis()
self.cache = RedisCacheBackend(self.redis)
handlers = [(r'/', CacheHandler)]
super(Application, self).__init__(handlers=handlers, **settings)
if __name__ == '__main__':
application = Application()
application.listen(8080)
tornado.ioloop.IOLoop.instance().start()
@javalurker

This comment has been minimized.

Copy link

commented Jul 12, 2017

有bug:
CacheMixin==>key = pickle.dumps((request.path, request.arguments))
可以改成:
CacheMixin==>key = pickle.dumps((request.path, request.method, request.arguments))

问题在于,如果一个url只有GET方式,但当有人恶意通过POST的方式访问的时候,页面返回错误信息,那么redis就会缓存这个错误信息“HTTPError: HTTP 403: Forbidden ('_xsrf' argument missing from POST)”。导致下次正常的GET方式,无法读取正确的内容(因为redis的key是存在的,value就是那个缓存的错误信息)

@marcelometal

This comment has been minimized.

Copy link

commented Aug 30, 2018

Hi @cloverstd, thank you for sharing this code. Could you please add a license for it? Can I share using GNU Affero General Public License?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.