Flask之请求钩子和异常捕获
请求钩子[hook]
在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:
- 在项目运行开始时,建立数据库连接;
- 在客户端请求开始时,根据需求进行权限校验;
- 在请求结束视图返回数据时,指定数据的交互格式;
为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设置的功能,即请求钩子。
请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子(注意:名字是固定的):
- before_first_request
- 在处理第一个请求前执行[项目初始化时的钩子]
- before_request
- 在每一次请求前执行
- 如果在某修饰的函数中返回了一个响应,视图函数将不再被调用
- after_request
- 如果没有抛出错误,在每次请求后执行
- 接受一个参数:视图函数作出的响应
- 在此函数中可以对响应值在返回之前做最后一步修改处理
- 需要将参数中的响应在此参数中进行返回
- teardown_request
- 在每一次请求后执行
- 接受一个参数:错误信息,如果有相关错误抛出
- 需要设置flask的配置DEBUG=False,teardown_request才会接受到异常对象。
app.py
代码
from flask import Flask, request # 初始化 app = Flask(import_name=__name__) @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.headers["Company"] = "python oldboy..." # 必须返回response参数 return response @app.teardown_request def teardown_request(exc): print("----teardown_request----") print("在每一次请求以后,执行这个钩子方法") print("如果有异常错误,则会传递错误异常对象到当前方法的参数中") # 在项目关闭了DEBUG模式以后,则异常信息就会被传递到exc中,我们可以记录异常信息到日志文件中 print(exc) # 编写路由视图 @app.route(rule='/') def index(): print("-----------视图函数执行了---------------") return "hello world!" if __name__ == '__main__': # 运行flask app.run(host="0.0.0.0", port=5000)
第一次请求
----before_first_request---- 系统初始化的时候,执行这个钩子方法 会在接收到第一个客户端请求时,执行这里的代码 ----before_request---- 每一次接收到客户端请求时,执行这个钩子方法 一般可以用来判断权限,或者转换路由参数或者预处理客户端请求的数据 -----------视图函数执行了--------------- ----after_request---- 在处理请求以后,执行这个钩子方法 一般可以用于记录会员/管理员的操作历史,浏览历史,清理收尾的工作 ----teardown_request---- 在每一次请求以后,执行这个钩子方法 如果有异常错误,则会传递错误异常对象到当前方法的参数中 None
第二次请求打印
----before_request---- 每一次接收到客户端请求时,执行这个钩子方法 一般可以用来判断权限,或者转换路由参数或者预处理客户端请求的数据 -----------视图函数执行了--------------- ----after_request---- 在处理请求以后,执行这个钩子方法 一般可以用于记录会员/管理员的操作历史,浏览历史,清理收尾的工作 ----teardown_request---- 在每一次请求以后,执行这个钩子方法 如果有异常错误,则会传递错误异常对象到当前方法的参数中 None
异常捕获
主动抛出HTTP异常
- abort 方法
- 抛出一个给定状态代码的 HTTPException 或者 指定响应,例如想要用一个页面未找到异常来终止请求,你可以调用 abort(404)
- 参数:
- code – HTTP的错误状态码
from flask import Flask, request, abort app = Flask(import_name=__name__) @app.route('/') def index(): # 主动抛出HTTP异常 if not request.args.get("uname"): abort(400) return "hello world!" if __name__ == '__main__': # 运行flask app.run(host="0.0.0.0", port=5000, debug=True)
注意点:
-
抛出状态码的话,只能抛出 HTTP 协议的错误状态码
-
abort在工作中基本不会被使用,工作中的异常抛出往往在业务错误的时候使用raise进行抛出错误类型,而不是抛出http异常。
-
abort一般用于权限等页面上错误的展示提示。
捕获错误
- errorhandler 装饰器
- 注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法
- 参数:
- code_or_exception – HTTP的错误状态码或指定异常
- errorhandler 可以捕获指定http状态码的异常
from flask import Flask, request, abort app = Flask(import_name=__name__) # errorhandler 可以捕获指定http状态码的异常 @app.errorhandler(400) def internal_server_error(e): print(e) # 400 Bad Request: The browser (or proxy) sent a request that this server could not understand. return '对不起,参数有误!' @app.route("/") def index(): # 主动抛出HTTP异常 if not request.args.get("uname"): abort(400) return "ok" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
- errorhandler捕获自定义的异常
from flask import Flask, request, abort app = Flask(import_name=__name__) # errorhandler 也可以捕获指定的内置异常或者自定义的异常 class APIError(Exception): pass # 捕获自定义异常 @app.errorhandler(APIError) def api_error(e): print(e) return "api请求有误" @app.route("/") def index(): # 抛出自定义异常并进行处理 raise APIError("api接口发生异常!!!!") return "ok" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
- 捕获标准异常[python内置声明的]
from flask import Flask, request, abort app = Flask(import_name=__name__) # 捕获标准异常[python内置声明的] @app.errorhandler(ZeroDivisionError) def zero_division_error(e): print(e) return '除数不能为0' @app.route("/") def index(): 1 / 0 return "ok" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
· Manus爆火,是硬核还是营销?