flask 路由、钩子函数
一、路由
1、常用路由参数:
flask的路由是基于装饰器的
- rule:路径,不能写正则
- methods=['GET','POST] : 允许的请求方式
- endpoint: 当前路由的别名---》反向解析用
- defaults:用于给 URL 路径中的参数提供默认值。这对于构建更具灵活性和容错性的 URL 路径规则非常有用
- redirect_to: 用于在访问某个 URL 路径时,自动重定向到另一条路径。它可以是一个字符串,或者是一个返回重定向目标的可调用对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | from flask import Flask, redirect, url_for app = Flask(__name__) @app .route( '/new_user_path' ) def new_user_path(): return "You've been redirected to the new user path." @app .route( '/old-user-path' , redirect_to = 'new_user_path' ) def redirect_old_path(): return '页面跳转' @app .route( '/user/<username>/page' , defaults = { 'page' : 1 }, methods = [ 'GET' , 'POST' ], endpoint = 'user_profile_default' ) @app .route( '/user/<username>/page/<int:page>' , methods = [ 'GET' , 'POST' ], endpoint = 'user_profile' ) def show_user(username, page): return f "User: {username}, Page: {page}" @app .route( '/home' ) def home(): return redirect(url_for( 'user_profile' , username = 'zjz' , page = 1 )) if __name__ = = '__main__' : app.run(debug = True ) |
补充:
1.1 一个视图函数可以有多个路由装饰器
1.2 使用 redirect_to
、redirect
和 url_for
可以处理 URL 重定向和生成
redirect_to
是一个用于路由装饰器中的快速重定向,通常用于将一个旧路径重定向到新的路径。这是在路由装饰器中指定的,而不是在函数实现中
redirect
是一个函数,通常在路由对应的视图函数内部使用,用于将用户请求重定向到新的 URL。
1 2 3 4 5 | from flask import redirect @app .route( '/some-path' ) def some_function(): return redirect( '/another-path' ) |
url_for
是一个用于生成 URL 的函数,它可以根据 Flask 应用中的路由定义生成外部 URL,非常适用于生成动态 URL,尤其是当路由的 URL 结构可能改变时。
1 2 3 4 5 6 7 8 9 10 11 | from flask import url_for @app .route( '/user/<username>/page/<int:page>' ) def show_user(username, page): return f "User: {username}, Page: {page}" @app .route( '/get-url' ) def get_url(): # 使用 url_for 生成 show_user 的 URL user_url = url_for( 'show_user' , username = 'john' , page = 2 ) return redirect(user_url) |
- **
redirect_to
**:主要用在路由装饰器中,它是一个快捷方式,用于将一个 URL 重定向到另一个指定的视图函数或 URL。 - **
redirect
**:用在视图函数内部,以编程方式将请求重定向到一个新的 URL。 - **
url_for
**:用于生成 URL,基于 URL 路由,确保生成的 URL 始终与定义的路由匹配,即使路由改变也能自动适配。
2、路由转换器
|
(默认)接受没有斜线的任何文本 |
|
接受正整数 |
|
接受正浮点值 |
|
类似 string ,但可以包含斜杠 |
|
接受UUID字符串 |
用例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | from flask import Flask app = Flask(__name__) @app .route( '/hello' , methods = [ 'GET' ]) def hello(): return "Hello, World!" @app .route( '/user/<username>' , methods = [ 'GET' ]) def show_user_profile(username): return f 'User: {username}' @app .route( '/post/<int:post_id>' , methods = [ 'GET' ]) def show_post(post_id): return f 'Post ID: {post_id}' @app .route( '/file/<path:filename>' , methods = [ 'GET' ]) def show_file(filename): return f 'File: {filename}' @app .route( '/uuid/<uuid:uid>' , methods = [ 'GET' ]) def show_uuid(uid): return f 'UUID: {uid}' if __name__ = = '__main__' : app.run(debug = True ) |
浏览器访问测试:
int转换器
file 转换器
uuid 转换器
3、其他写法
1 2 3 | @app .route + methods 不写methods 默认只有get - @app.get - @app.post |
4、自己注册路由不使用装饰器
app.add_url_rule('/', view_func=hello)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | from flask import Flask app = Flask(__name__) @app .route( '/hello' , methods = [ 'GET' ]) def hello(): return "Hello, Jingzhiz!" app.add_url_rule( '/' , view_func = hello) if __name__ = = '__main__' : app.run(debug = True , port = 6001 ) |
补充:路由系统本质
-装饰器---> 本质是 self.add_url_rule(rule, endpoint, f, **options)
-self是 Flask(__name__) app对象
源码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def route( self , rule: str , * * options: t. Any ) - > t. Callable : def decorator(f: t. Callable ) - > t. Callable : endpoint = options.pop( "endpoint" , None ) self .add_url_rule(rule, endpoint, f, * * options) return f return decorator @setupmethod def add_url_rule( self , rule: str , endpoint: t.Optional[ str ] = None , view_func: t.Optional[t. Callable ] = None , provide_automatic_options: t.Optional[ bool ] = None , * * options: t. Any , ) - > None : raise NotImplementedError |
二、钩子函数
1、@app.before_request 和 @app.after_request
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | from flask import Flask app = Flask(__name__) @app .before_request def before1(): print ( 'before1' ) @app .before_request def before2(): print ( 'before2' ) return '第二个返回了' @app .before_request def before3(): print ( 'before3' ) @app .after_request def after1(response): print ( 'after1' ) return response @app .after_request def after2(response): print ( 'after2' ) return response @app .after_request def after3(response): print ( 'after3' ) return response @app .route( '/' ) def index(): # put application's code here return '返回了' if __name__ = = '__main__' : app.run() |
结果 :
before_request: 一旦返回了有效值,则后续的 @app.before_request 和视图函数将不在执行,这里 before3() 和 index() 不再执行
after_request
:在视图函数处理完成并生成响应后,从下往上依次执行所有的 after_request
函数。这个流程不会中断,所以所有的 after_request
函数都会执行。
2、before_request
的使用场景
before_request
钩子函数在每个请求到达视图函数之前执行。这允许在正式处理请求之前进行一些预处理操作。以下是一些常见的使用场景:
2.1 用户认证与授权:
在访问任何受保护的路由之前检查用户是否已登录。
校验用户是否有权限访问特定资源。
1 2 3 4 | @app .before_request def check_authentication(): if not is_user_authenticated(): return redirect( '/login' ) |
2.2 初始化上下文和资源:
在每个请求开始时,初始化一些全局变量、数据库连接或其他资源。
1 2 3 | @app .before_request def initialize_globals(): g.some_data = load_some_data() |
2.3 记录请求的信息用于审计或分析
1 2 3 | @app .before_request def log_request_info(): print (f 'Handling request for {request.path}' ) |
2.4 防止CSRF攻击:
验证请求中的CSRF令牌,确保请求是从可信来源发出的。
1 2 3 4 5 6 | @app .before_request def protect_from_csrf(): if request.method = = "POST" : token = request.form.get( 'csrf_token' ) if not token or token ! = session.get( 'csrf_token' ): abort( 403 ) |
3、after_request
的使用场景
after_request
钩子函数在视图函数处理完请求后执行,允许对响应进行附加处理。这可以用来添加全局的后处理逻辑。以下是一些常见的使用场景:
3.1 修改或增强响应:
添加或修改HTTP头
增加默认的响应格式,如增加跨域资源共享(CORS)头
1 2 3 4 | @app .after_request def add_cors_headers(response): response.headers[ 'Access-Control-Allow-Origin' ] = '*' return response |
3.2 记录响应日志:
记录响应的相关信息,用于监控或分析。
1 2 3 4 | @app .after_request def log_response_info(response): print (f 'Returned status: {response.status}' ) return response |
3.3 缓存控制:
修改响应头部以控制缓存策略
1 2 3 4 5 | @app .after_request def add_cache_control(response): if request.endpoint = = 'static' : response.headers[ 'Cache-Control' ] = 'public, max-age=31536000' return response |
3.4 清理资源:
请求结束后进行资源的清理或释放,例如关闭数据库连接。
1 2 3 4 | @app .after_request def release_resources(response): close_database_connection() return response |
3.5 安全增强:
增加安全相关的头部,如内容安全政策(Content Security Policy, CSP)。
1 2 3 4 | @app .after_request def set_security_headers(response): response.headers[ 'Content-Security-Policy' ] = "default-src 'self'" return response |
4、@app.teardown_request
1 2 3 4 | @app .teardown_request def jingzhiz(err): print (err) # 每一个请求之后绑定一个函数,即使遇到了异常。如果视图函数正常顺利运行,err是None的,如果视图函数出错了,err就是错误对象,一般用来做日志记录 print ( 'teardown_request' ) |
@app.after_request
和 @app.teardown_request
总结对比
特性 | @app.after_request | @app.teardown_request |
---|---|---|
调用时机 | 请求处理完成后、响应发送前 | 请求结束后,无论成功与否 |
返回值 | 必须返回一个响应对象 | 返回 None (无需返回响应) |
用途 | 修改响应对象或添加自定义响应头 | 清理资源、处理请求期间的错误 |
是否与异常相关 | 与异常无关 | 可以处理请求过程中发生的异常 |
适用场景
- 使用
@app.after_request
当你需要修改响应,或设置响应头时。 - 使用
@app.teardown_request
当你需要进行资源清理或错误处理时。
5、@app.errorhandler
1 2 3 4 | @app .errorhandler( 404 ) def error(arg): print ( '404测试' , arg) return render_template( '404.html' ) |
6、@app.template_global() 和 @app.template_filter()
是Flask中用于模板处理的两个装饰器,它们可以让你在Jinja2模板中定义全局变量和自定义过滤器,帮助你更灵活地处理模板中的数据。
6.1 @app.template_global()
1 2 3 4 5 6 7 8 9 10 11 | from flask import Flask app = Flask(__name__) @app .template_global() def greet(name): return f "Hello, {name}!" @app .route( '/' ) def index(): return render_template( 'index.html' ) |
在html 页面中使用变量
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> {{ greet( 'World' ) }} <! - - 输出:Hello, World! - - > < / body> < / html> |
6.2 @app.template_filter()
用于创建自定义的Jinja2过滤器。这些过滤器可以在模板中用于格式化数据,类似于内置的过滤器(如 str.upper
)。
1 2 3 4 5 6 7 8 9 10 11 | from flask import Flask app = Flask(__name__) @app .template_filter() def reverse(s): return s[:: - 1 ] @app .route( '/' ) def index(): return render_template( 'index.html' ) |
在 index.html
模板中,该自定义过滤器可以在管道操作中使用:
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html> <html lang = "en" > <head> <meta charset = "UTF-8" > <title>Title< / title> < / head> <body> {{ "Hello, World!" | reverse }} <! - - 输出:!dlroW ,olleH - - > < / body> < / html> |
- **
@app.template_global()
**:用于注册全局函数,便于模板随时调用。适合逻辑较复杂且在多处地方使用的操作。 - **
@app.template_filter()
**:用于注册自定义过滤器,在模板中对数据进行处理。适用于需要在模板中重复使用的格式化操作。