扩展知识、Flask请求与响应、session的使用和原理、session源码分析

扩展知识

https://liuqingzheng.top/article/1/05-CGI,FastCGI,WSGI,uWSGI,uwsgi%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82/
    
服务器			框架
wsgiref			django
uWSGI			django
werkzeug		flask
tornado			tornado框架

# 1 flask python 微小的web框架,整个服务可以放在一个文件中,也可以做成很大的项目,需要借助于第三方
	-flask和django :django内置了很多:后台管理,用户和权限管理,session,缓存,消息框架,自定制命令,flask只保留了基本的请求与响应处理
    
# 2 wsgi协议:Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口
	-之前部署路飞:uwsgi跑在8888端口,使用了uwsgi协议跑的,所以不能接受http协议,用浏览器直接访问8888,有问题,咱们访问了8080【nginx】---->把http协议转成uwsgi协议----》8888
	-测试阶段,使用wsgiref运行django,监听的就是http协议,浏览器中可以直接访问

image

# 3 flask快速使用:咱们讲的使用没有区别,源码动了一些
	-1.x :
	-2.x :大动了
    	-变量定义指定类型
            #原来:
            current_app=LocalProxy()
            #现在,指定了变量current_app是Flask类型
            current_app:"Flask" = LocalProxy()
        -函数传参和返回值指定类型
        	# 原来:
              def index(name, cv):
            	pass
            # 现在,公司里用的多
              def index(name:str, cv:ContextVar[t.Any])->None:
            	pass

Flask请求与响应

请求对象

1 request.method		# 提交的方法
2 request.args			# get请求提交的数据
3 request.form			# post请求提交的数据
4 request.values		# post和get提交的数据总和
5 request.cookies		# 客户端所带的cookie
6 request.headers		# 请求头
7 request.path			# 不带域名,请求路径
8 request.full_path 	 # 不带域名,带参数的请求路径
9 request.script_root	 
10 request.url			 
11 request.base_url		 # 带域名请求路径
12 request.url_root		 
13 request.host_url		 
14 request.host			 
15 request.files		 
16 request.data			# django中的body	 

响应对象

@app.route('/',methods=['GET','POST'])
def index():
    # 1四件套
        # -render_template
        # -redirect
        # -jsonify
        # -''
    # 2写入响应头-->没有响应对象,先做出一个响应对象
    # from .wrappers import Response
    res='helloe'
    res=make_response(res)
    # 往Response的对象中,放入响应头
    res.headers['name']='zxr'
    # 3 写入cookie
    # res.set_cookie('xx','xx')
    res.delete_cookie('xx')
    '''
    key, 键
    value=’’, 值
    max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止
    expires=None, 超时时间(IE requires expires, so set it if hasn’t been already.)
    path=’/‘, Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
    domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=”.example.com”所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
    secure=False, 浏览器将通过HTTPS来回传cookie
    httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
    '''
    return res

image

前后端分离和混合

# 前后端混合,cookie是后端写入的
	res.set_cookie('xx','xx')混合都是这么写的,这样写了,浏览器就会把cookie保存到cookie中
    本质是后端吧cookie放到响应头中,浏览器读到响应头中有cookie,把cookie写入到浏览器中
# 前后端分离后
	直接把客户端要存到cookie中的数据,放到响应体中
	前端(浏览器,app,小程序),自己取出来,放到相应的位置
    	浏览器使用js自己写入到cookie
    	app 自己使用代码写入到某个位置

session的使用和原理

image

# 以django为例
	登录视图函数以后-->request.session['name'] = 'zxr'
        1 生成一个随机字符串
        2 把session字典序列化放到django_session表中
        3 以session为key,随机字符串为value,写入到cookie中
        
	下次再来的时候,会携带者随机字符串,在中间件中根据sessionid取出随机字符串去django_session表中,根据这个随机字符串取出value值,然后解密,得到字典,字典放到request.session,就可以拿到上次我们存进去的那个字典
	
	所以django的中间件既写了request又写response
    
	虽然是在视图函数中写的,但是是在中间件中执行的
	
	如果request.session为空,不做任何事,如果不为空,有更改--->重新写入session表中的value,没改过的话不做任何事

image

# flask框架
	登录视图函数,判断session是否为空,不为空,又加了东西,把这个字典序列化成字符串然后使用密钥加密,把加密的字符串以cookie的形式写入浏览器(就会看到session对应的一个随机字符串,而且是三段式的)
    下次访问一个需要登录的视图函数,进入视图函数之前,根据session取出三段式,然后进行反序列化,解密得到session对象,在后续的视图函数中使用

session的使用

# 放值 视图函数中
导入全局的session
session['name']='lqz'

# 取值 视图函数中
导入全局的session
print(session['name'])

session源码分析

# 整个flask,从请求进来,到请求走的整个流程
    def wsgi_app(self, environ, start_response):
        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: 
                error = sys.exc_info()[1]
                raise
            return response(environ, start_response)
        finally:
            ctx.pop(error)
            
            
            
   # ctx.push 的 373行左右	
  		if self.session is None:
            session_interface = self.app.session_interface
            self.session = session_interface.open_session(self.app, self.request)
            if self.session is None:
                self.session = session_interface.make_null_session(self.app)
                
   # app.session_interface  就是Flask对象中有个session_interface对象
			SecureCookieSessionInterface()
    			-open_session:请求来了,从cookie中取出三段串,反序列化解密放到session中
        		-save_session:请求走了,把session字典中的值,序列化加密,放到cookie中
            
            
            
  # open_session:请求来了执行
    def open_session(self, app, request) :
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        # val 就是取出的三段:eyJhZ2UiOiIxOSIsIm5hbWUiOiJscXoifQ.Y5ac9g.vOomQFqFuaqXWqRQhvSNyc61UIk
        val = request.cookies.get('session')
        if not val:
            return self.session_class()
        max_age = int(app.permanent_session_lifetime.total_seconds())
        try:
            data = s.loads(val, max_age=max_age)
            return self.session_class(data)
        except BadSignature:
            return self.session_class()
        
        
  # save_session:请求走了执行
	 def save_session(self, app, session, response):
        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)

        if not session:  # 如果视图函数放了,不为空 session['name']='lqz'
            if session.modified:  # 
                response.delete_cookie(
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )

            return

  
        if session.accessed:
            response.vary.add("Cookie")

        if not self.should_set_cookie(app, session):
            return

        expires = self.get_expiration_time(app, session)
        # 序列化--->加密了
        val = self.get_signing_serializer(app).dumps(dict(session))  # type: ignore
        # 三段:
        response.set_cookie(
            name, # session
            val,  # 三段:
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )
1 请求来的时候,会执行open_session--->取出cookie,判断是否为空,如果不为空,把它反序列化,解密--->字典--->转到session对象中--->视图函数
    
2 请求走的时候,会执行save_session--->把session转成字典--->序列化加密--->三段--->放到cookie中
posted @ 2022-12-13 19:08  张张包~  阅读(67)  评论(0编辑  收藏  举报