session和cookie的关系
cookie:保存在客户端浏览器上的键值对
session_id = "eyJ1c2VyX2luZm8iOiJ"
session:保存在服务器上的键值对
{
"eyJ1c2VyX2luZm8iOiJ":{'is_login':True, 'user':'standby',...},
"iJhbGV4In0.DYUE4A.A":{'is_login':True, 'user':'alex',...},
...
}
- 用户第一次打开浏览器请求我的网站页面
- 在服务器端生成一个随机字符串,作为value发给客户端浏览器。
- 这个随机字符串在服务器的session中作为key,value={},保存起来。
知识准备
1. 通过给定字符串,如何实例化一个对象出来?
import importlib
path = "session_code.RedisSession"
md,cls = path.rsplit('.',maxsplit=1)
m = importlib.import_module(md)
cls = getattr(m,cls)
print(cls.__name__)
或者
import importlib
path = "scrapy.middleware.MiddlewareManager"
tmp_li = path.split('.')
cls_name = tmp_li.pop()
prefix = '.'.join(tmp_li)
m = importlib.import_module(prefix)
cls = getattr(m,cls_name)
print(cls.__name__)
rest_framework/setting.py
def import_from_string(val, setting_name):
"""
Attempt to import a class from a string representation.
"""
try:
# Nod to tastypie's use of importlib.
module_path, class_name = val.rsplit('.', 1)
module = import_module(module_path)
return getattr(module, class_name)
except (ImportError, AttributeError) as e:
msg = "Could not import '%s' for API setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
raise ImportError(msg)
from django.utils.module_loading import import_string
def import_string(dotted_path):
"""
Import a dotted module path and return the attribute/class designated by the
last name in the path. Raise ImportError if the import failed.
"""
try:
module_path, class_name = dotted_path.rsplit('.', 1)
except ValueError:
msg = "%s doesn't look like a module path" % dotted_path
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
module = import_module(module_path)
try:
return getattr(module, class_name)
except AttributeError:
msg = 'Module "%s" does not define a "%s" attribute/class' % (
module_path, class_name)
six.reraise(ImportError, ImportError(msg), sys.exc_info()[2])
2. 面向对象里的 __setitem__ __getitem__
class Foo(object):
def __getitem__(self, item):
return "123"
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print('----')
self.__dict__.pop(key)
obj = Foo()
print(obj['k1']) # __getitem__
obj['k1'] = 666 # __setitem__
del obj['k1'] # __delitem__
Django 里面操作session:
request.session['xxx'] = xxxxx
3. 程序结合配置文件以及工厂模式
class MemSession(object):
def __getitem__(self, item):
return "123"
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print('----')
self.__dict__.pop(key)
class RedisSession(object):
def __getitem__(self, item):
return "123"
def __setitem__(self, key, value):
self.__dict__[key] = value
def __delitem__(self, key):
print('----')
self.__dict__.pop(key)
class SessionFactory(object):
"""
工厂模式
settings.py : SESSION_ENGINE = "session_code.RedisSession"
"""
@staticmethod
def get_session(self):
import settings
engine = settings.SESSION_ENGINE
import importlib
module_path,cls_name = engine.split('.',maxsplit=1)
md = importlib.import_module(module_path)
cls = getattr(md,cls_name)
return cls
Tornado基于内存和redis的session组件实现示例
app.py
from tornado import ioloop
from tornado.web import RequestHandler,Application
from session_code import SessionFactory
settings = {
'template_path':'templates',
}
class SessionHandler(object):
def initialize(self):
cls = SessionFactory.get_session()
self.session = cls(self)
class IndexHandler(SessionHandler,RequestHandler):
def get(self):
user = self.session['user']
if user:
self.write("首页欢迎你")
else:
self.redirect('/login')
class LoginHandler(SessionHandler,RequestHandler):
def get(self):
self.render('login.html',msg="")
def post(self, *args, **kwargs):
name = self.get_argument('name')
pwd = self.get_argument('pwd')
if 'alex'==name and '123' == pwd:
self.session['user'] = name
self.redirect('/index')
else:
self.render('login.html',msg="用户名或密码错误")
application = Application([
(r"/index", IndexHandler,{},'alias_name1'),
(r"/login", LoginHandler,{},'alias_name2'),
],**settings)
if __name__ == "__main__":
application.listen(8090)
ioloop.IOLoop.instance().start()
session_code.py
import json
import time
import hashlib
import settings
def gen_random_str():
md5 = hashlib.md5()
md5.update(str(time.time()).encode('utf-8'))
return md5.hexdigest()
class MemSession(object):
''' 静态字段在类里只保存一份(不管实例化多少次,用的都是同一份) '''
container = {}
def __init__(self,handler):
self.handler = handler
self.session_id = settings.SESSION_ID
self.expires = settings.EXPIRES
self.initial()
def initial(self):
client_random_str = self.handler.get_cookie(self.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] = {} # 给服务端设置session
expires = time.time() + self.expires
self.handler.set_cookie(self.session_id,self.random_str,expires=expires) # 给客户端设置cookie
def __getitem__(self, item):
return self.container[self.random_str].get(item)
def __setitem__(self, key, value):
self.container[self.random_str][key] = value
print(self.container)
def __delitem__(self, key):
if key in self.container[self.random_str]:
del self.container[self.random_str][key]
class RedisSession(object):
def __init__(self,handler):
self.handler = handler
self.session_id = settings.SESSION_ID
self.expires = settings.EXPIRES
self.initial()
def get_redis_conn(self):
import redis
conn = redis.Redis(host='8.8.8.8', port=6379)
return conn
def initial(self):
self.redis_conn = self.get_redis_conn()
client_random_str = self.handler.get_cookie(self.session_id)
if client_random_str and self.redis_conn.exists(client_random_str):
self.random_str = client_random_str
else:
self.random_str = gen_random_str()
expires = time.time() + self.expires
self.handler.set_cookie(self.session_id,self.random_str,expires=expires) # 给客户端设置cookie
self.redis_conn.expire(self.random_str,self.expires) # 给redis设置超时时间
def __getitem__(self, item):
# redis 返回的是byte类型,所以需要decode
data_str = self.redis_conn.hget(self.random_str,item)
if data_str:
return json.loads(data_str.decode('utf-8'))
def __setitem__(self, key, value):
# val = {'type':type(value).__name__,'value':value}
self.redis_conn.hset(self.random_str,key,json.dumps(value))
def __delitem__(self, key):
self.redis_conn.hdel(self.random_str,key)
class SessionFactory(object):
"""
工厂模式
"""
@staticmethod
def get_session():
import settings
engine = settings.SESSION_ENGINE
import importlib
module_path,cls_name = engine.split('.',maxsplit=1)
md = importlib.import_module(module_path)
cls = getattr(md,cls_name)
return cls
settings.py
SESSION_ENGINE = "session_code.RedisSession"
SESSION_ID = "__session_id__"
EXPIRES = 300
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 class="c1">Login</h1>
<form action="" method="post">
<input type="text" name="name">
<input type="text" name="pwd">
<input type="submit" value="提交"> {{ msg }}
</form>
</body>
</html>