自己做考试题目网站,域名制作网站,学校门户网站建设报告,跨境电商app排行本文首发于公众号#xff1a;Hunter后端 原文链接#xff1a;Flask笔记六之中间件操作 与 Django 一样#xff0c;Flask 也提供了中间件的使用#xff0c;用于在处理请求之前和之后执行一些公共逻辑
本篇笔记的代码都已经提交到 github 上#xff0c;可使用下面的操作获取… 本文首发于公众号Hunter后端 原文链接Flask笔记六之中间件操作 与 Django 一样Flask 也提供了中间件的使用用于在处理请求之前和之后执行一些公共逻辑
本篇笔记的代码都已经提交到 github 上可使用下面的操作获取代码
git clone https://github.com/x1204604036/flask_backend.git1、Django 中间件使用示例
在 Django 中我们可以先定义一个中间件然后在 settings.py 中注册中间件的内容大致如下
# huter/middleware.pyclass SimpleMiddleware:def __init__(self, get_response):self.get_response get_responsedef __call__(self, request):# 在请求进入视图函数前的可以执行一些操作针对 requestprint(request.path)response self.get_response(request)# 在处理完请求后可以执行一些操作针对 response# log_response_info()return response在 Django 中请求处理前的 request 参数和处理后返回的 response 都可以在一个中间件里操作完成
2、Flask 的中间件介绍
在 Flask 中中间件通过装饰器来使用被分为两部分一个是请求前用 app.before_request 来操作一个是请求后用 app.after_request 来操作。
接下来介绍一下中间件从注册到使用的操作。
1. 中间件定义
这里我们定义两个测试用的中间件我们在 app/utils/ 文件夹下创建一个 middlewares 的文件夹其下再创建一个文件 middlewares.py
# app/utils/middlewares/middlewares.pydef register_middleware(app):app.before_requestdef before_request_test():print(before request)app.after_requestdef after_request_test(response):print(after request)return responseapp.before_request 修饰的函数表示在请求处理前进行的操作这里是简单的打印一条消息除此之外我们还可以在这里对登录进行验证。
这样的话在前面的笔记里我们对接口进行的 login_required 的装饰器就不需要了就不要在每个接口前都进行这种装饰可以使代码变得简洁同样实现我们想要的功能
除此之外还可以对请求的信息进行日志记录比如请求的接口名称啊请求的参数啊等等
app.after_request 修饰的函数表示在请求处理完成后进行的操作我们可以对返回的 response 的数据增加一些参数等其中一个 response 的内容我们打印出它的 response.__dict__ 可以看到它的数据结构如下所示
# response.__dict__{_charset: utf-8, headers: Headers([(Content-Type, application/json), (Content-Length, 75)]), _status: 200 OK, _status_code: 200, direct_passthrough: False, _on_close: [], response: [b{\n code: 0,\n msg: success,\n user_info: {\n user_id: 1\n }\n}\n]}当然上面的操作还需要在 app 中注册之后才可以使用。
2. 中间件引入注册
要使用中间件则需要进行引入注册操作在这里即为调用上面的 register_middleware() 函数我们在 app/__init__.py 中操作如下
# app/__init__.pyfrom app.utils.middlewares.middlewares import register_middlewaredef create_app():app Flask(__name__)register_middleware(app)return app引入后重启服务然后调用一个接口就可以看到日志里会输出前面测试的两个中间件打印出的信息
接下来我们创建两个中间件用于实现登录的校验和接口请求的日志记录在此之前先介绍一下 Flask 里的 g 对象
3、g 对象
Flask 里有一个 g 对象的概念它可以用于在一个请求周期内存储共享的临时数据但是仅限于一个请求周期。
比如客户端发起了两次请求我们在第一个请求里保存到 g 对象里的数据就随着第一个请求的 response 的返回就销毁了第二次请求是一个全新的 g 对象。
这个其实和 session 对象有相似之处但是 session 是跨请求周期的比如第一个接口登录保存了 user_id 登录信息第二个接口再次请求还可以读取到这个信息
介绍 g 对象是因为后面我们在中间件中可以用到一些信息这些信息的传递就可以通过 g 对象的方式来操作。
以下是 g 对象的赋值与取值操作 from flask import gg.user_id 1print(g.user_id)在这里我将所有需要给 g 对象赋值的数据都在一个函数里完成这里我创建了一个文件app/utils/init_g_object.py
其中内容如下
from flask import g, request, sessiondef init_g_object(app):app.before_requestdef init_g_object_info():g.request_path request.pathg.user_id session.get(user_id)g.ip_address request.remote_addrg 对象数据的初始化在 app/__init__.py 中
# app/__init__.pyfrom app.utils.init_g_object import init_g_objectdef create_app():app Flask(__name__)init_g_object(app)return app4、Flask 中间件使用实例
这里给两个中间件使用的实例一个中间件做登录验证操作一个做接口的日志记录
分别在 app/utils/middlewares/ 文件夹下创建两个文件login_required_middleware.py 和 request_log_middleware.py
其内容如下
# login_required_middleware.pyfrom flask import g
from app.utils.exception_handler import UserExceptionclass LoginRequiredMiddleware:def check_login(self):return True if g.user_id is not None else Falsedef check_login_essential(self):url_path g.request_pathouter_url_list [/user/login, /user/register]return True if url_path not in outer_url_list else Falsedef check(self):need_check self.check_login_essential()if need_check:if not self.check_login():raise UserException(code-1, msgnot login, http_code401)在这个中间件中我们先判断当前请求的路径是否是需要登录才可访问的如果是则判断 g 对象中是否有登录信息也就是 user_id这个在前面给 g 对象初始化信息的时候有写入
如果需要登录但是没有登录则直接返回一个报错信息
请求的日志记录中间件内容如下
# request_log_middleware.pyimport logging
import time
from flask import glogger logging.getLogger()class RequestLogMiddleware:def log_info(self):total_time time.time() - g.start_timelog_info request_path: {}, request_user: {}, spend_time: {}, ip_address: {}.format(g.request_path,g.user_id,total_time,g.ip_address,)logger.info(log_info)这个中间件是在请求处理完成之后的逻辑在这个中间件中我们直接根据当前时间减去 g 对象的开始时间这个字段下面会有定义是在请求开始前写入的然后将请求路径请求用户总耗时和请求的 IP 地址写入日志。
如果有需要还可以将请求参数和返回参数也写入日志方便之后的查询
然后在 middlewares.py 中定义
# app/utils/middlewares/middlewares.pyfrom .login_required_middleware import LoginRequiredMiddleware
from .request_log_middleware import RequestLogMiddleware
from flask import g
import timedef register_middleware(app):app.before_requestdef record_start_time():g.start_time time.time()app.before_requestdef login_required():LoginRequiredMiddleware().check()app.after_requestdef request_log_info(response):RequestLogMiddleware().log_info()return response在中间件的注册中因为后面的日志记录需要用到请求开始的时间所以这里定义了一个 record_start_time() 函数用于记录开始时间方便后面计算总时长。
5、before_request 中的返回
这里有一点需要注意下所有被 app.before_request 装饰的函数如果有返回值那么则直接返回不再接着往后面执行逻辑比如下面的
def register_middleware(app):app.before_requestdef test_return():return {msg: test return}app.before_requestdef test2():passapp.after_requestdef test3(response):return responseapp.after_requestdef test4(response):return response在这里before_request 的顺序执行的先执行 test_return() 再执行 test2()但是因为 test_return() 有返回值所以整个请求流程直接结束了
而对于 after_request 修饰的函数它是逆序执行的也就是先执行 test4()再执行 test3()