在 Flask 中,中间件(Middleware)和扩展(Extensions)是增强应用功能的两大支柱。
- 中间件:像“过滤器”或“拦截器”,在请求到达视图函数之前或响应返回给客户端之后执行通用逻辑(如日志、认证、CORS)。
- 扩展:像“插件”,为 Flask 添加特定的重型功能(如数据库 ORM、用户登录管理、表单验证)。
一、 Flask 中间件 (Middleware)
Flask 基于 Werkzeug WSGI 工具包,因此它的中间件机制遵循标准的 WSGI 规范。你可以通过两种方式实现中间件:
1. 使用 @app.before_request 和 @app.after_request (最常用)
这是 Flask 内置的“轻量级中间件”机制,适合处理与请求/响应直接相关的逻辑。
from flask import Flask, request, g
import time
app = Flask(__name__)
# 1. 请求前执行 (Before Request)
@app.before_request
def before_req():
# 记录请求开始时间
g.start_time = time.time()
print(f"Request started: {request.method} {request.path}")
# 2. 请求后执行 (After Request)
@app.after_request
def after_req(response):
# 计算耗时并添加到响应头
duration = time.time() - g.start_time
response.headers['X-Response-Time'] = f"{duration:.4f}s"
print(f"Request finished with status: {response.status_code}")
return response # 必须返回 response 对象2. 使用 WSGI 中间件类 (高级/全局)
如果你需要介入更底层的 WSGI 流程(例如在所有 Flask 逻辑之前修改环境),可以编写一个标准的 WSGI 中间件类,并将其包装在 app.wsgi_app 上。
class MyCustomMiddleware:
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
# 在这里可以修改 environ 字典
environ['MY_CUSTOM_VAR'] = 'Hello from Middleware'
# 调用下一个应用(即 Flask app)
return self.app(environ, start_response)
# 注册中间件
app.wsgi_app = MyCustomMiddleware(app.wsgi_app)3. 常见中间件场景
- CORS (跨域资源共享):允许前端不同域名访问 API。
- Compression: 自动压缩响应内容(Gzip)。
- Logging: 记录所有请求的详细日志。
- Authentication: 检查 Header 中的 Token。
二、 Flask 扩展 (Extensions)
Flask 核心非常精简,复杂功能都通过扩展实现。扩展通常以 Flask- 开头命名。
🏆 必装的“四大金刚”扩展
| 扩展名 | 用途 | 安装命令 |
|---|---|---|
| Flask-SQLAlchemy | 数据库 ORM (操作 MySQL/PostgreSQL/SQLite) | pip install flask-sqlalchemy |
| Flask-Migrate | 数据库版本管理 (基于 Alembic) | pip install flask-migrate |
| Flask-WTF | 表单处理与 CSRF 保护 | pip install flask-wtf |
| Flask-Login | 用户会话管理 (登录/登出/记住我) | pip install flask-login |
其他常用扩展
- Flask-CORS: 处理跨域问题 (
pip install flask-cors) - Flask-Mail: 发送邮件 (
pip install flask-mail) - Flask-RESTful / Flask-Marshmallow: 构建 REST API
- Flask-Caching: 缓存支持 (Redis/Memcached)
- Flask-JWT-Extended: JSON Web Token 认证 (适合前后端分离/API)
三、 如何正确初始化扩展?(应用工厂模式)
在大型项目中,为了避免循环导入并支持测试,我们使用应用工厂模式。扩展的初始化分为两步:实例化 和 绑定。
1. 定义扩展实例 (extensions.py)
只创建对象,不绑定 app。
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
db = SQLAlchemy()
migrate = Migrate()
login_manager = LoginManager()2. 在工厂中初始化 (app/__init__.py)
from flask import Flask
from .extensions import db, migrate, login_manager
def create_app():
app = Flask(__name__)
app.config.from_object('config.Config')
# ⚠️ 关键步骤:调用 init_app 将扩展绑定到当前 app
db.init_app(app)
migrate.init_app(app, db)
login_manager.init_app(app)
# 配置 Login Manager
login_manager.login_view = 'auth.login'
# 注册蓝图...
return app四、 实战示例:集成 Flask-CORS 和 Flask-Login
1. 解决跨域 (Flask-CORS)
如果你的前端运行在 localhost:3000,后端在 localhost:5000,浏览器会阻止请求。
pip install flask-corsfrom flask_cors import CORS
def create_app():
app = Flask(__name__)
# 简单用法:允许所有域 (开发环境方便,生产环境需限制)
CORS(app)
# 高级用法:只允许特定域
# CORS(app, resources={r"/api/*": {"origins": "https://myfrontend.com"}})
return app2. 用户登录保护 (Flask-Login)
保护某些路由只有登录用户才能访问。
pip install flask-loginfrom flask_login import LoginManager, login_user, logout_user, login_required, current_user
login_manager = LoginManager()
# 加载用户的回调函数
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@app.route('/dashboard')
@login_required # ⭐ 装饰器:如果未登录,自动重定向到登录页
def dashboard():
return f'Hello, {current_user.username}'
@app.route('/login', methods=['POST'])
def login():
user = User.query.filter_by(username=request.form['username']).first()
if user and check_password_hash(user.password, request.form['password']):
login_user(user) # 建立会话
return redirect(url_for('dashboard'))
return 'Login failed', 401💡 最佳实践建议
- 不要重复造轮子:在写复杂功能(如发邮件、连数据库、做认证)前,先搜一下有没有成熟的 Flask 扩展。
- 按需引入:Flask 的优势是轻量。如果只是一个简单的内部工具,可能只需要
Flask-SQLAlchemy,不需要引入沉重的Flask-Admin或Celery。 - 注意扩展兼容性:某些扩展可能不再维护。优先选择社区活跃、文档齐全、最近一年有更新的扩展。
- 中间件顺序:如果有多个 WSGI 中间件,注意它们的包裹顺序。内层的中间件先执行。
📝 总结
- 小逻辑、请求级处理 → 用
@before_request/@after_request。 - 底层拦截、全局修改 → 用 WSGI 中间件类。
- 重型功能(DB, Auth, Form) → 用 Flask 扩展。
- 初始化扩展 → 记得在应用工厂中使用
init_app(app)。
掌握了中间件和扩展,你就拥有了组装强大 Flask 应用的“乐高积木”。接下来,你想深入了解某个具体扩展(如 SQLAlchemy 高级查询 或 JWT 认证),还是学习如何部署你的应用?