关于Cookie和Session
简单的说
- Cookie是保存在浏览器的键值对
- Session是保存在服务端的键值对
- Session是依赖于Cookie的
在Django框架中,我们可以直接操作cookie和session,但是tornado只支持cookie,那如果要使用session怎么办呢?自己定义session
基于内存实现SESSION
我们知道,在tornado
中,所有的请求都是由RequestHandler
对象来处理(以下简称handler
对象)。在RequestHandler
源码中,预留了一个钩子方法initialize
,该方法会在实例化Handler
对象时执行。因此,如果我们继承RequestHandler
类并重写initialize
,就可以完成一些自定义操作。
import os import tornado.ioloop import tornado.web from tornado.web import RequestHandler import hashlib import time # 生成一个随机的字符串 def gen_random_str(): md5 = hashlib.md5() md5.update(str(time.time()).encode('utf-8')) return md5.hexdigest() class CacheSession(object): container = {} def __init__(self,handler): self.handler = handler client_random_str = self.handler.get_cookie("_session_id_") if client_random_str and client_random_str in self.container: self.random_str = client_random_str else: self.random_str = gen_random_str() self.container[self.random_str] = {} expires = time.time() + 300 self.handler.set_cookie("_session_id_", self.random_str, expires=expires) def __setitem__(self, key, value): self.container[self.random_str][key] = value def __getitem__(self, item): return self.container[self.random_str].get(item) class SessionHandler(RequestHandler): def initialize(self): # self指代的是当前的对象 self.session = CacheSession(self) class LoginHandler(SessionHandler,RequestHandler): def get(self, *args, **kwargs): self.render('login.html') def post(self, *args, **kwargs): username = self.get_argument('username') password = self.get_argument('password') if username == 'admin' and password == '123': self.session['username'] = username self.redirect('/main') else: self.redirect('/login') class MainHandler(SessionHandler,RequestHandler): def get(self, *args, **kwargs): username = self.session['username'] if username: self.write('this is main page') else: self.redirect('/login') def post(self, *args, **kwargs): pass settings = { "static_path" : os.path.join(os.path.dirname(__file__),'static'), "static_url_prefix":"static", "template_path":'views', "xsrf_cookies": True, } def make_app(): return tornado.web.Application([ (r"/login", LoginHandler), (r"/main", MainHandler), ], **settings) if __name__ == "__main__": app = make_app() app.listen(8888) tornado.ioloop.IOLoop.current().start()
代码解释
-
定义一个
Session
类,其实例化时接收handler
对象- 在
Session
类中定义一个静态字段(大字典),用来存储session_id
和对应的用户信息;所有的session
对象都可以访问这个大字典。 - 在
Session
的构造方法中,获取和设置cookie
:- 调用handler对象
get_cookie()
方法获取session_id
,如果没有,则生成一段随机字符串random_str
作为session_id
- 将
session_id
写入大字典 - 调用
handler
对象的set_cookie()
方法,通知浏览器设置cookie:set-cookie: {session_id: random_str}
- 调用handler对象
- 在
Session
类中,定义__getitem__
,__setitem__
,__delitem__
方法来实现通过字典的方式操作session
对象
- 在
-
在
initialize
方法中为handler
对象增加session
属性,其值是Session
对象:self.session=Session(self)
;在每个路由对应的视图中都重写initialize
方法太麻烦了,利用面向对象的多继承,将这一步单独写在一个类SessionHandler
,所以视图类先继承这个类即可 - 每次请求进来,都会执行
SessionHandler
中的initialize
方法,并实例化Session
对象,从而获取session_id
- 操作
session
:- 通过
self.session[key] = value
, 即可调用session对象的__setitem__
方法来写session
; - 通过
self.session[key]
即可调用session
对象的__getitem__
方法来获取session
- 通过
del self.session[key]
即可调用session
对象的__delitem__
方法来删除session
- 通过
基于Redis实现Session
import os import tornado.ioloop import tornado.web from tornado.web import RequestHandler import hashlib import time def gen_random_str(): md5 = hashlib.md5() md5.update(str(time.time()).encode('utf-8')) return md5.hexdigest() class RedisSession(object): @property def conn(self): import redis conn = redis.Redis(host='192.168.11.96', port=6379) return conn def __init__(self,handler): self.handler = handler client_random_str = self.handler.get_cookie("_session_id_") if client_random_str and self.conn.exists(client_random_str): self.random_str = client_random_str else: self.random_str = gen_random_str() expires = time.time() + 300 self.handler.set_cookie("_session_id_", self.random_str, expires=expires) self.conn.expire(self.random_str, 300) def __setitem__(self, key, value): self.conn.hset(self.random_str, key, value) def __getitem__(self, item): return self.conn.hget(self.random_str, item) class SessionHandler(RequestHandler): def initialize(self): self.session = RedisSession(self)
工厂模式实现Session
session_code.py
class SessionFactory(object): @staticmethod def get_session(): import settings import importlib engine = settings.SESSION_ENGINE module_path,cls_name = engine.rsplit('.',maxsplit=1) md = importlib.import_module(module_path) cls = getattr(md,cls_name) return cls
app.py
from session_code import SessionFactory cls = SessionFactory.get_session() print(cls)
setting.py
SESSION_ENGINE = "session_code.RedisSession" # SESSION_ENGINE = "session_code.CacheSession" SESSION_ID = "__session__id__" EXPIRERS = 300
原创作者:马一特
文章出处:http://www.cnblogs.com/mayite/
版权声明:自由转载-非商用-非衍生-保持署名
(创意共享4.0许可证)
转载说明:如果文章对您有帮助,欢迎点赞,评论加转载,赠人玫瑰,手留余香
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?