三、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才会接受到异常对象。

"""请求钩子"""
@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 ) # 异常处理对象
课上代码参考一下,以下方代码实现为主
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

猜你喜欢

转载自www.cnblogs.com/yijue-lu/p/10952309.html