Flask入门教程(十六):中间件与扩展——增强应用功能的两种机制

1. Flask中间件

Flask的中间件是对请求和响应进行处理的钩子,通常用于在请求到达视图函数之前或在响应发送到客户端之前执行一些操作。中间件可以用于日志记录、请求修改、响应修改、性能监控等。

1.1 请求钩子(推荐方式)

请求钩子允许你在处理请求的不同阶段插入代码,Flask提供了四种钩子:

装饰器 触发时机 典型用途
@app.before_request 每个请求处理之前 权限验证、数据库连接、请求日志
@app.after_request 每个请求处理之后,响应返回之前 添加响应头、压缩响应内容
@app.teardown_request 请求结束后(无论是否发生异常) 释放资源、关闭数据库连接
@app.before_first_request 应用第一次处理请求之前(仅执行一次) 初始化全局资源、预热缓存

app.py

复制代码
from flask import Flask, request

app = Flask(__name__)

@app.before_request
def before_request():
    print('Before request')
    # 可以在这里做权限检查,如果未认证可提前返回响应
    # if not session.get('user'):
    #     return redirect('/login')

@app.after_request
def after_request(response):
    print('After request')
    # 添加自定义响应头
    response.headers['X-Request-Time'] = '123ms'
    return response

@app.teardown_request
def teardown_request(exception):
    print('Teardown request')
    # 清理资源,如关闭数据库连接
    # 如果有异常,exception参数包含异常对象

@app.before_first_request
def before_first_request():
    print('第一次请求前执行(仅一次)')

@app.route('/')
def index():
    return 'Hello, World!'

多个钩子的执行顺序

复制代码
请求到达
    │
    ▼
@app.before_first_request(仅第一次请求执行)
    │
    ▼
@app.before_request(按注册顺序执行)
    │
    ▼
路由匹配 → 视图函数执行
    │
    ▼
@app.after_request(按注册逆序执行)
    │
    ▼
响应返回客户端
    │
    ▼
@app.teardown_request(异常时也执行)

1.2 蓝图中的请求钩子

蓝图也支持独立的请求钩子,只作用于该蓝图的路由:

复制代码
# auth.py
from flask import Blueprint

bp = Blueprint("auth", __name__)

@bp.before_request
def check_auth():
    """只对auth蓝图的路由生效"""
    if request.endpoint not in ("auth.login", "auth.register"):
        if "username" not in session:
            return redirect(url_for("auth.login"))

1.3 自定义WSGI中间件

除了请求钩子,Flask还允许你创建自定义WSGI中间件类,在更底层对请求和响应进行操作。

middleware.py

复制代码
class CustomMiddleware:
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        def custom_start_response(status, headers):
            # 在响应头中添加自定义字段
            headers.append(('X-Custom-Header', 'Value'))
            return start_response(status, headers)

        # 可以在这里修改请求环境(environ)
        # environ['REMOTE_USER'] = 'custom_user'

        return self.app(environ, custom_start_response)

app.py

复制代码
from flask import Flask
from middleware import CustomMiddleware

app = Flask(__name__)

# 将自定义中间件包装到wsgi_app上
app.wsgi_app = CustomMiddleware(app.wsgi_app)

@app.route('/')
def index():
    return 'Hello, World!'

请求钩子比自定义WSGI中间件更简单、更符合Flask风格,优先推荐使用请求钩子 。只有当需要修改WSGI底层环境(如environ)时才考虑自定义中间件。

2. Flask扩展

Flask扩展是用于为Flask应用添加功能的插件,可以集成第三方库,提供例如数据库集成、表单处理、用户认证等功能。

2.1 常见的Flask扩展

扩展 功能 安装命令
Flask-SQLAlchemy 数据库ORM集成 pip install flask-sqlalchemy
Flask-WTF 表单处理与验证 pip install flask-wtf
Flask-Login 用户会话管理与认证 pip install flask-login
Flask-Migrate 数据库迁移管理 pip install flask-migrate
Flask-Mail 发送电子邮件 pip install flask-mail
Flask-CORS 跨域资源共享 pip install flask-cors
Flask-Caching 缓存支持 pip install flask-caching
Flask-RESTful RESTful API开发 pip install flask-restful
Flask-SocketIO WebSocket实时通信 pip install flask-socketio
Flask-Admin 管理后台快速搭建 pip install flask-admin

2.2 安装和使用Flask扩展

以Flask-SQLAlchemy为例:

复制代码
pip install flask-sqlalchemy

app.py

复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)

@app.route('/')
def index():
    return 'Hello, World!'

2.3 延迟初始化模式

在工厂模式(create_app)中,扩展通常采用延迟初始化:

复制代码
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

# 先创建扩展实例(不绑定应用)
db = SQLAlchemy()

def create_app():
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'
    
    # 在工厂函数中绑定应用
    db.init_app(app)
    
    return app

3. 创建自定义扩展

如果现有的扩展不能满足你的需求,你可以创建自己的扩展。

3.1 简单自定义扩展

myextension.py

复制代码
class MyExtension:
    def __init__(self, app=None):
        self.app = app
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        app.config.setdefault('MY_EXTENSION_CONFIG', 'default_value')
        app.after_request(self.after_request)

    def after_request(self, response):
        response.headers['X-My-Extension'] = 'MyValue'
        return response

app.py

复制代码
from flask import Flask
from myextension import MyExtension

app = Flask(__name__)
my_ext = MyExtension(app)

@app.route('/')
def index():
    return 'Hello, World!'

3.2 支持配置的自定义扩展

复制代码
class MyExtension:
    def __init__(self, app=None):
        if app is not None:
            self.init_app(app)

    def init_app(self, app):
        # 设置默认配置,用户可通过app.config覆盖
        app.config.setdefault('MY_EXTENSION_ENABLED', True)
        app.config.setdefault('MY_EXTENSION_TIMEOUT', 30)
        
        # 注册请求钩子
        app.before_request(self.before_request)
        
        # 将扩展实例挂载到app上,方便其他地方使用
        app.my_extension = self

    def before_request(self):
        """在请求前执行的操作"""
        pass

4. 中间件vs扩展对比

对比维度 中间件(请求钩子) 扩展
用途 请求/响应处理、日志、权限验证 集成第三方库、添加新功能
实现方式 @app.before_request等装饰器 Python类 + init_app()
作用范围 全局或蓝图级别 全局,按需注册
复杂度 简单 从简单到复杂不等
典型场景 请求日志、响应头添加、权限检查 数据库、表单、认证、缓存

5. 常用扩展配置速查

扩展 初始化方式 关键配置
Flask-SQLAlchemy db = SQLAlchemy(app) SQLALCHEMY_DATABASE_URI
Flask-WTF app.secret_key = '...' WTF_CSRF_ENABLED
Flask-Login login_manager.init_app(app) LOGIN_VIEW
Flask-Migrate migrate = Migrate(app, db)
Flask-Mail mail = Mail(app) MAIL_SERVER, MAIL_PORT
Flask-CORS CORS(app) CORS_ORIGINS

小结

本章全面讲解了Flask的中间件与扩展机制。中间件方面,请求钩子(before_requestafter_requestteardown_requestbefore_first_request)是处理请求前后逻辑的推荐方式,蓝图也支持独立的钩子;自定义WSGI中间件通过包装app.wsgi_app实现更底层的控制。扩展方面,Flask拥有丰富的扩展生态(SQLAlchemy、WTF、Login、Migrate等),通过pip install安装后使用扩展类(app)扩展类().init_app(app)方式集成;自定义扩展可封装可复用的功能。合理使用中间件和扩展,能大大增强Flask应用的功能和可维护。

相关推荐
烂蜻蜓2 小时前
Flask入门教程(十二):表单处理——从基础到Flask-WTF完整实践
后端·python·flask
jay神2 小时前
【计算机毕业设计】基于Flask+Vue的电影数据可视化与智能推荐系统
前端·vue.js·python·信息可视化·flask·毕业设计·课程设计
满怀冰雪3 小时前
24-PaddleClas 模型评估、导出与推理部署入门
大数据·人工智能·python·深度学习·paddle
DeepVisionary9 小时前
谷歌 Gemini Omni 1.1 Flash 正式发布:4K 视频、40 秒场景延伸,视频生成进入按 token 计费时代
python·自动化
阡之尘埃9 小时前
Python数据分析案例85——大模型微调全流程(SFT的LoRA微调)
人工智能·python·深度学习·语言模型·llm·微调·千问
海兰9 小时前
【应用】基于 Next.js 16 + Python mplfinance的金融K线图与技术指标可视化平台(三)
javascript·python·金融
cvcode_study9 小时前
Ollama+ComfyUI 多模态
大数据·人工智能·python
星核0penstarry11 小时前
试一试用gr.Workflow把AI多步骤串联变成可视化画布
人工智能·python·ai作画·api·ai编程·工作流·api聚合平台