您的位置:首页 > 其它

flask_session_源码剖析

2018-01-08 19:59 447 查看
开始文件(部分):

from flask import Flask,request,session
app = Flask(__name__)
app.secret_key = 'sdfsdfsd'
from flask.sessions import SessionInterface,SessionMixin
import uuid
import json
from flask.sessions import SessionInterface
from flask.sessions import SessionMixin
from itsdangerous import Signer, BadSignature, want_bytes

class MySession(dict, SessionMixin):
def __init__(self, initial=None, sid=None):
self.sid = sid
self.initial = initial
super(MySession, self).__init__(initial or ())

def __setitem__(self, key, value):
super(MySession, self).__setitem__(key, value)

def __getitem__(self, item):
return super(MySession, self).__getitem__(item)

def __delitem__(self, key):
super(MySession, self).__delitem__(key)

class MySessionInterface(SessionInterface):
session_class = MySession
container = {
# 'asdfasdfasdfas':{'k1':'v1','k2':'v2'}
# 'asdfasdfasdfas':"{'k1':'v1','k2':'v2'}"
}

def __init__(self):
pass
# import redis
# self.redis = redis.Redis()

def _generate_sid(self):
return str(uuid.uuid4())

def _get_signer(self, app):
if not app.secret_key:
return None
return Signer(app.secret_key, salt='flask-session',
key_derivation='hmac')

def open_session(self, app, request):
"""
程序刚启动时执行,需要返回一个session对象
"""
sid = request.cookies.get(app.session_cookie_name)
if not sid:
# 生成随机字符串,并将随机字符串添加到 session对象中
sid = self._generate_sid()
return self.session_class(sid=sid)

signer = self._get_signer(app)
try:
sid_as_bytes = signer.unsign(sid)
sid = sid_as_bytes.decode()
except BadSignature:
sid = self._generate_sid()
return self.session_class(sid=sid)

# session保存在redis中
# val = self.redis.get(sid)
# session保存在内存中
val = self.container.get(sid)

if val is not None:
try:
data = json.loads(val)
return self.session_class(data, sid=sid)
except:
return self.session_class(sid=sid)
return self.session_class(sid=sid)

def save_session(self, app, session, response):
"""
程序结束前执行,可以保存session中所有的值
如:
保存到resit
写入到用户cookie
"""
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
httponly = self.get_cookie_httponly(app)
secure = self.get_cookie_secure(app)
expires = self.get_expiration_time(app, session)

val = json.dumps(dict(session))

# session保存在redis中
# self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
# session保存在内存中
self.container.setdefault(session.sid, val)

session_id = self._get_signer(app).sign(want_bytes(session.sid))

response.set_cookie(app.session_cookie_name, session_id,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)

app.session_interface = MySessionInterface()
# app.session_interface = Foo()
# app.session_interface
# app.make_null_session()
@app.route('/index')
def index():
print('网站的所有session',MySessionInterface.container)
print(session)
session['k1'] = 'v1'
session['k2'] = 'v2'
del session['k1']

# 在内存中操作字典....
# session['k1'] = 'v1'
# session['k2'] = 'v2'
# del session['k1']

return "xx"

if __name__ == '__main__':
app.__call__
app.run()


 

# 1. 执行Flask类的__call__
class RequestContext(object):
def __init__(self,environ):
self.environ = environ

def push(self):
# 3

# 请求相关数据,加到local中: stack.push...
_request_ctx_stack.push(self)

# 获取cookie中的随机字符串,检验是否有,没有就生成
# 根据随机字符串,获取服务端保存的session的
# {
#     'xxxxxxx': {...}
#     'xxxxxxx': {...}
# }
# 新用户: {}
# 老用户:{user:'xxx'}
self.session = self.app.open_session(self.request)
if self.session is None:
self.session = self.app.make_null_session()

class Flask:
def process_response(self, response):
# 8
# 执行 after_request装饰器
for handler in funcs:
response = handler(response)

# 将内存中的session持久化到:数据库、....
if not self.session_interface.is_null_session(ctx.session):
self.save_session(ctx.session, response)

return response

def finalize_request(self, rv, from_error_handler=False):
# 7
response = self.make_response(rv)
try:
response = self.process_response(response)
request_finished.send(self, response=response)
except Exception:
if not from_error_handler:
raise
self.logger.exception('Request finalizing failed with an '
'error while handling an error')
return response

def full_dispatch_request(self):
# 5

# 触发只执行一次的装饰器函数,@before_first_request
self.try_trigger_before_first_request_functions()
try:
# 触发Flask的信号,没用: pip3 install blinker
request_started.send(self)

# 执行特殊装饰器:before_request
# 如果没有返回值,rv=None;有返回值 “嘻嘻嘻”
rv = self.preprocess_request()
if rv is None:
# 触发执行视图函数
rv = self.dispatch_request()
except Exception as e:
rv = self.handle_user_exception(e)

# 6 对返回值进行封装
return self.finalize_request(rv)

def wsgi_app(self, environ, start_response):

# 处理request,将请求添加到local中
ctx = self.request_context(environ)
# 2.处理request和session
ctx.push()

error = None
try:
try:
# 4 执行视图函数
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
# 9
ctx.auto_pop(error)

def __call__(self, environ, start_response):
"""Shortcut for :attr:`wsgi_app`."""
# 1.xxx
return self.wsgi_app(environ, start_response)


源码流程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: