1 session源码?
1 app.session_interface 默认是某个类的对象,以后全局对象 session,就是SecureCookieSessionInterface()的对象
2 请求来了,会执行这个对象的: open_session方法
3 请求走了,会执行这个对象的:save_session方法
4 找出上面讲的--》读源码--》
app.run()---->run_simple(地址, 端口, self可调用对象)--->self 是谁?就是 app
请求来了,就会执行 self可调用对象()--->app()---->对象加括号---》触发---》类的__call__
请求来了,就会执行flask类的 __call__--->self.wsgi_app(environ, start_response)
def wsgi_app(self, environ: dict, start_response: t.Callable) -> t.Any:
ctx = self.request_context(environ)
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if "werkzeug.debug.preserve_context" in environ:
environ["werkzeug.debug.preserve_context"](_cv_app.get())
environ["werkzeug.debug.preserve_context"](_cv_request.get())
if error is not None and self.should_ignore_error(error):
error = None
ctx.pop(error)
# 5 ctx.push()--->有如下代码
if self.session is None: # 请求刚来,是空的
#session_interface 就是SecureCookieSessionInterface类的对象
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
#6 SecureCookieSessionInterface类的open_session
from flask.sessions import SecureCookieSessionInterface
open_session步骤:
1 会去cookie中取出session对应的 三段式的字符串
2 解密,校验签名---》把这个数据--》放到 session对象中
save_session步骤:
1 从session取出数据
2 加密,签名---放到cookie中
3 返回给前端
1.1 save_session
'''
1 视图函数中,咱们 session[name]=lqz
2 请求走了,会触发save_session
3 触发save_session时:
把session中的数据,加密签名得到三段字符串
放到cookie中,放到了浏览器中
'''
def save_session(
self, app: Flask, session: SessionMixin, response: Response
) -> None:
name = self.get_cookie_name(app)
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
# Add a "Vary: Cookie" header if the session was accessed at all.
if session.accessed:
response.vary.add("Cookie")
# If the session is modified to be empty, remove the cookie.
# If the session is empty, return without setting the cookie.
if not session:
if session.modified:
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
response.vary.add("Cookie")
return
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
# 加密,签名---放到cookie中
val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore
response.set_cookie(
name,
val, # type: ignore
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
response.vary.add("Cookie")
1.2 open_session
'''
1 请求来了,request中带着cookie(也有可能没有)
2 根据 session这个key,取出value,如果有,就是 我们当时生成的三段
3 字典=s.loads(value) 把内容验签,解密出来,转成了字典
4 把这个字典转到 session对象中
5 以后视图函数中 session[name] 就能取到当时你放的name
'''
def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None:
s = self.get_signing_serializer(app)
if s is None:
return None
# val 就是那三段
val = request.cookies.get(self.get_cookie_name(app))
if not val:
# 如果没有带cookie,造个空session,返回
return self.session_class()
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
data = s.loads(val, max_age=max_age)
# 解密,校验签名---》把这个数据--》放到 session对象中
return self.session_class(data)
except BadSignature:
return self.session_class()
1.3. django session的控制
from django.contrib.sessions.middleware import SessionMiddleware
Django内置的会话控制简称Session,可为访问者提供基础的数据存储。数据主要存储在服务器上,并且网站的任意站点都能使用会话数据。
当用户第一次访问网站时,网站的服务器将自动创建一个Session对象,该Session对象相当于该用户在网站的一个身份凭证,而且Session能存储该用户的数据信息。当用户在网站的页面之间跳转时,存储在Session对象中的数据不会丢失,只有Session过期或被清理时,服务器才将Session中存储的数据清空并终止该Session。
在创建Django项目时,Django已默认启用Session功能,Session是通过Django的中间件实现的,可以在配置文件settings.py中找到相关信息。
django中Session默认使用数据库保存相关的数据信息,如果想变更Session的保存方式,可以在settings.py中添加配置信息SESSION_ENGINE,该配置可以指定Session的保存方式。Django提供了5种Session的保存方式:
#settings.py
#数据库保存方式,默认方式,无须在setting.py中配置
SESSION_ENGINE = ‘django.contrib.sessions.backends.db’
#以文件形式保存
SESSION_ENGINE = ‘django.contrib.sessions.backends.file’
#使用文本保存可设置文件保存路径,/mysite 代表项目根目录
SESSION_FILE_PATH = '/mysite'
#以缓存形式保存
SESSION_ENGINE = ‘django.contrib.sessions.backends.cache’
#设置缓存名,默认是内存缓存方式,此处的设置于缓存机制的设置相关
SESSION_CACHE_ALIAS = 'default'
#以数据库 + 缓存形式保存
SESSION_ENGINE = ‘django.contrib.sessions.backends.cached_db’
#以cookies形式保存
SESSION_ENGINE = ‘django.contrib.sessions.backends.signed_cookies’
2 闪现?
# flash 翻译过来的
# 假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
# 以后遇到,在当次请求有数据要存,下次请求还能取出来,就可以使用闪现
### 设置闪现
# 1 普通使用 :通过闪现---》放进去,取一次,就没了
# flash(s) # 放到闪现中了,加密放到了cookie总
# 2 分类,以分类放入
flash(s, category='xxx')
flash('xxx', category='yyy')
### 取闪现
# 1 普通取,全取出来 从闪现中取出来
# err = get_flashed_messages()[0]
# 2 根据分类取
err = get_flashed_messages(category_filter=['xxx'])[0]
# 总结:
1 设置flash,可以按分类设置
2 去flash,在当前请求中,可以取出多次,都是在的
3 一旦有请求取出,再去别的的请求中取,就没了,无论有没有分类,都没了
4 请求扩展 ?
# django 中中间件,对所有请求拦截
# flask中使用请求扩展实现
django flask
-process_request----》before_request
-process_response--->after_request
# 就是django中间件
请求头中判断有没有user-agent 做反扒
响应头中加入 跨域的
from flask import Flask, session, redirect, request, flash, get_flashed_messages,make_response
app = Flask(__name__)
app.secret_key = 'asdfasdf'
app.debug = True
@app.before_request
def before():
# 做统一处理,处理校验失败,不让他继续往后走了
'''
return None---->继续走下一个请求扩展
return 新手四件套
'''
print('来了')
@app.before_request
def before2():
# 做统一处理,处理校验失败,不让他继续往后走了
'''
return None---->继续走下一个请求扩展
return 新手四件套
'''
print('来了222')
# return '不行了'
@app.after_request
def after(response):
print('走了')
# return response
return make_response('你看到我了')
@app.route('/')
def home():
print('home')
return 'home'
@app.route('/order')
def order():
return 'order'
if __name__ == '__main__':
app.run()