session原理,闪现,请求扩展,中间件,蓝图

session的原理

flask的session源码分析

# 通过app.session_interface()----->可以找到SecureCookieSessionTnterface()类的对象
-open_session:请求来了,从cookie中取出字符串,把字符串反序列化成session对象
 def open_session(
        self, app: "Flask", request: "Request"
    ) -> t.Optional[SecureCookieSession]:
        s = self.get_signing_serializer(app)
        if s is None:
            return None
        val = request.cookies.get(self.get_cookie_name(app))
        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:请求走时,把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)
        if not session:
            if session.modified:
                response.delete_cookie(
                    name,
                    domain=domain,
                    path=path,
                    secure=secure,
                    samesite=samesite,
                    httponly=httponly,
                )
            return
        # Add a "Vary: Cookie" header if the session was accessed at all.
        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,
            val,  # type: ignore
            expires=expires,
            httponly=httponly,
            domain=domain,
            path=path,
            secure=secure,
            samesite=samesite,
        )

闪现

主要作用:假设在a页面操作出错,跳转到b页面,在b页面显示a页面的错误信息
		-本质其实就是在a页面,把错误信息放到了某个位置,在b页面把错误取出来
    
放值:
	 flash(message='信息错误')
     分类: flash(message='信息错误',category='error')
        
取值:get_flashed_messages()
	 按分类取值: get_flashed_messages(category_filter=['error'])
    
    
    
'''
	等同于djagno的message框架
'''

请求扩展

before_request

作用:类比django中间件的peocess_request,在请求到来执行路由函数之前先执行,但是如果有多个,顺序是从上往下执行

应用:基于它做用户登录认证

'''
注意:如果before_request的返回值不是None的情况下,返回的而是别的值,那么后续的请求都不会执行,本次请求直接返回,如果定义了after_request那么会接着它执行, 最终本次请求响应结束。
'''

@app.before_request
def process_request(*args,**kwargs):
    if request.path == '/login':
        return None
    user = session.get('user_info')
    if user:
        return None
    return redirect('/login') 

after_request

作用: 类比django中间件中的process_response,如果请求没有出现异常的情况下, 会在请求返回return之前执行. 但是如果有多个顺序是从下往上执行.

@app.after_request  # 后执行
def process_response1(response):
    print('process_response1 走了')
    return response

@app.after_request  # 先执行
def process_response2(response):
    print('process_response2 走了')
    return response

before_first_request

作用:项目启动起来接收到第一次请求时执行

应用:项目初始化用来保证以后项目只要不重启就不再继续执行

@app.before_first_request
def first():
    print('我的第一次')

teardown_request

作用: 在每一个路由函数执行完毕之后执行,即使遇到了异常也会执行. (提示: 返回reutrn没有任何的效果, 不能控制返回的结果)

应用: 记录日志

@app.teardown_request  
def ter(e):  # e就是上一个路由函授执行过程中出现被捕获的异常信息.
    print(e)
    print('我是teardown_request ')

errorhandler

作用: 绑定错误的状态码进而可以捕获服务器的错误, 并返回对应的错误页面.

@app.errorhandler(500)
def error_500(arg):
    return render_template('error.html', message='500错误')


@app.errorhandler(404)
def error_404(arg):
    return render_template('error.html', message='404错误')

'''
	arg: 错误信息
'''

template_global------全局的标签

作用: 全局的标签, 在任意的html页面中就可以直接使用, 不需要在render_template中传递参数以后才能使用.

@app.template_global()
def sb(a1, a2):
    return a1 + a2

# html页面中直接使用, 不需要传递参数.
{{ sb(1,2) }}

template_filter-----过滤器

@app.template_filter()
def db(a1, a2, a3):
    return a1 + a2 + a3

# html页面中直接使用, 不需要传递参数. 其中1传递给a1, 2传递给a2, 3传递给a3. (提示: Django中的过滤器最多只可以传递二个参数)
{{ 1|db(2,3) }}

总结:

1.重点掌握before_request和after_request

2.注意有多个的情况,执行顺序

3.before_request请求拦截后(也就是return了值或者Response对象(jsonify,render_template,redirect))

中间件

class Md(object):
    def __init__(self, old_wsgi_app):
        self.old_wsgi_app = old_wsgi_app

    def __call__(self, environ, start_response):
        print('开始之前')
        ret = self.old_wsgi_app(environ, start_response)
        print('结束之后')
        return ret


if __name__ == '__main__':
    # 1. 我们发现当执行app.run方法的时候,最终执行run_simple,最后执行app(),也就是在执行app.__call__方法
    # 2. 在__call__里面,执行的是self.wsgi_app().那我们希望在执行他本身的wsgi之前做点事情。
    # 3. 所以我们先用Md类中__init__,保存之前的wsgi,然后我们用将app.wsgi转化成Md的对象。
    # 4. 那执行新的的app.wsgi_app,就是执行Md的__call__方法。
    # 5. 最后把原来的wsgi_app替换为自定义的

    app.wsgi_app = Md(app.wsgi_app)
    app.run()

蓝图

    由于项目开发是一个非常耗时间和精力的工程,如果我们将所有的Flask请求方法都写在同一个文件下的话,非常不便于我们代码管理和后期功能代码的添加。
    如下示例:我们在一个文件中写入多个路由,这会使代码维护变得困难。
如图所示,如果我们将所有的请求方法写在同一个处理文件下面的话,会导致我们的代码显得很没有逻辑性,如果我们后期想要修改代码或者添加新功能的话,就会显得很突兀,不知道如何下手,此时就需要我们提到的蓝图来解决这个问题,如果学过django可能了解过django中的app,django中app的主要作用就是将django项目分成一个个单独的app模块,然后将所有app分配不同的处理功能,通过路由分配将它们连接成一个大django项目,其实Flask中的蓝图和django中的app功能大同小异,下面我们大概的了解一下Flask的蓝图,代码如下

   我们首先创建一个主的路由配置文件manage.py,该文件主要的作用就是启动整个的Flask框架(项目),如图所示
 接着,我们在manage.py的平级目录下创建两个文件admin.py 、user.py,我们大概看一下两个文件的内容
 这两个文件相当于django中两个app,不同是django中路由分配是将总路由通过include分配给app的urls.py路由文件,而Flask是通过蓝图注册方式将蓝图添加到主app中,user.py,admin.py主要是创建蓝图,然后为创建的蓝图添加路由配置,接着我们就可以在主路由文件manage.py中将我们创建的蓝图注册到主app中。
这样配置好以后就可以实现路由分层管理,我们来试一下,运行主程序manage.py
在浏览器中访问所设置的路由

补充

蓝图还能实现类似django中的路由分发功能,或者叫路由前缀

user.py:
    from flask import Blueprint
    user = Blueprint('user', __name__, url_prefix='/user/')
    '''
    	url_prefix:路由前缀
    '''
    @user.route('/user/hello')
    def hello():
        return '/user/hello'
    
    
'''
原来的路由为 http://127.0.0.1:5000/user/hello

现在的路由为 http://127.0.0.1:5000/user/user/hello

在原有路由前加了前缀
'''
posted @ 2022-08-09 15:46  春游去动物园  阅读(31)  评论(0编辑  收藏  举报