三、Flask_会话控制与请求钩子
1. 会话控制
会话控制: cookie 和 session
在flask中会话控制的保存主要通过request和response来完成
session本质上就是保存在服务端中的一个文件,文件中存储了用户的会话信息[我们开发者设置进行的用户登录状态或者访问历史]
session依赖于cookie来实现,因为用户在每次请求服务端时,需要客户端发送属于当前用户的session文件名,一般这个文件名在客户端中使用cookie来保存的,名称一般是session_id
from flask import reuqest # 请求对象 获取cookie信息
from flask import make_response # 响应对象 设置cookie信息
会话的开始是在用户打开浏览器以后第一次访问网站.
会话的结束时在用户关闭浏览器以后
因为 http 是一种无状态协议,浏览器请求服务器是无状态的。
无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。
无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。
有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等
实现状态保持主要有两种方式:
-
在客户端存储信息使用Cookie,本地存储,token[jwt,oauth]
-
在服务器端存储信息使用Session,redis
1.1 Cookie
Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。
使用场景: 登录状态, 浏览历史, 网站足迹
Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用
Cookie基于域名安全,不同域名的Cookie是不能互相访问的
如访问luffy.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到luffy.com写的Cookie信息
浏览器的同源策略针对cookie也有限制作用.
当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息
1.1.1 设置cookie
设置cookie需要通过flask的Response响应对象来进行设置,由flask内部提供了一个make_response函数给我们可以快速创建响应对象
from flask import make_response @app.route("/cookie/set_cookie") def set_cookie(): """设置cookie""" # return "python" response = make_response("python") # 这一句代码和上面一句代码是一样 response.set_cookie("uid","100",max_age=30,path="/cookie") return response
1.1.2 获取cookie
@app.route("/demo/get_cookie") def get_cookie(): # 获取cookie print( request.cookies ) uid = request.cookies.get("uid","cookie失效了") return uid
1.2 Session
对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,如用户名、余额、等级、验证码等信息
在服务器端进行状态保持的方案就是Session
注意: Session依赖于Cookie,而且flask中使用session,需要配置SECRET_KEY选项,否则报错.
1.2.1 设置session
from flask import session @app.route("/set_session") def set_session(): """设置session""" session["user_name"] = "小灰灰" return "ok"
1.2.2 获取session
@app.route("/get_session") def get_session(): """获取session""" uname = session.get("user_name","session数据没有了") return uname
2. 请求钩子
-
在请求开始时,建立数据库连接;
-
在请求开始时,根据需求进行权限校验;
-
在请求结束时,指定数据的交互格式;
为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设置的功能,即请求钩子。
请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:
-
before_first_request
-
在处理第一个请求前执行
-
-
before_request
-
在每次请求前执行
-
如果在某修饰的函数中返回了一个响应,视图函数将不再被调用
-
-
after_request
-
如果没有抛出错误,在每次请求后执行
-
接受一个参数:视图函数作出的响应
-
在此函数中可以对响应值在返回之前做最后一步修改处理
-
需要将参数中的响应在此参数中进行返回
-
-
teardown_request:
-
在每次请求后执行
-
接受一个参数:错误信息,如果有相关错误抛出
-
需要设置flask的配置DEBUG=False,teardown_request才会接受到异常对象。
-
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
"""请求钩子""" @app.before_first_request def before_first(): print("项目初始化以后第一次被访问!") @app.before_request def before_request(): print("项目每一次被访问,视图执行之前,都会执行这个钩子!") @app.after_request def after_request(response): print("项目每一次被访问,视图执行之后,都会执行这个钩子!") return response # 使用这个钩子,是在debug=Flase才有效果 @app.teardown_request def teardown_request(exc): print("项目每一次被访问,视图执行以后,都会执行这个钩子! 一旦发生错误,会把错误对象传递到当前钩子") print( exc ) # 异常处理对象
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from flask import Flask from settings.dev import DevConfig app = Flask(__name__) # 项目配置 app.config.from_object(DevConfig) @app.before_first_request def before_first_request(): print("----before_first_request----") print("系统初始化的时候,执行这个钩子方法") print("会在接收到第一个客户端请求时,执行这里的代码") @app.before_request def before_request(): print("----before_request----") print("每一次接收到客户端请求时,执行这个钩子方法") print("一般可以用来判断权限,或者转换路由参数或者预处理客户端请求的数据") @app.after_request def after_request(response): print("----after_request----") print("在处理请求以后,执行这个钩子方法") print("一般可以用于记录会员/管理员的操作历史,浏览历史,清理收尾的工作") response.headers["Content-Type"] = "application/json" # 必须返回response参数 return response @app.teardown_request def teardown_request(exc): print("----teardown_request----") print("在每一次请求以后,执行这个钩子方法,如果有异常错误,则会传递错误异常对象到当前方法的参数中") print(exc) @app.route("/") def index(): print("----视图函数----") print("视图函数被运行了") return "视图函数被运行了<br>" if __name__ == '__main__': app.run(host="0.0.0.0", port=80)
在第1次请求时的打印:
----before_first_request---- 系统初始化的时候,执行这个钩子方法 会在接收到第一个客户端请求时,执行这里的代码 ----before_request---- 每一次接收到客户端请求时,执行这个钩子方法 一般可以用来判断权限,或者转换路由参数或者预处理客户端请求的数据 ----视图函数---- 视图函数被运行了 ----after_request---- 在处理请求以后,执行这个钩子方法 一般可以用于记录会员/管理员的操作历史,浏览历史,清理收尾的工作 ----teardown_request---- 在每一次请求以后,执行这个钩子方法,如果有异常错误,则会传递错误异常对象到当前方法的参数中 None
在第2次请求时的打印:
----before_request---- 127.0.0.1 - - [08/Apr/2019 09:23:53] "GET / HTTP/1.1" 200 - 每一次接收到客户端请求时,执行这个钩子方法 一般可以用来判断权限,或者转换路由参数或者预处理客户端请求的数据 ----视图函数---- 视图函数被运行了 ----after_request---- 在处理请求以后,执行这个钩子方法 一般可以用于记录会员/管理员的操作历史,浏览历史,清理收尾的工作 ----teardown_request---- 在每一次请求以后,执行这个钩子方法,如果有异常错误,则会传递错误异常对象到当前方法的参数中 None