Flask以“微框架”闻名,其核心设计体现了“约定优于配置”的反向哲学,这种设计理念的三大支柱为:
对比技术:Flask vs Django
特性 | Flask | Django |
项目结构 | 自由灵活 | 严格约定 |
学习曲线 | 低(适合初学者) | 中高(需掌握完整生态) |
适用场景 | 快速原型/API服务/微服务 | 全栈Web应用/内容管理系统 |
扩展性 | 通过扩展按需集成 | 内置完整功能套件 |
Flask通过LocalStack实现线程隔离的请求上下文,确保多线程环境下请求数据的独立性。
from flask import request
@app.route('/')
def index():
user_agent = request.headers.get('User-Agent') # 访问请求头
return f'Your browser is {user_agent}'
基于Werkzeug的Map和Rule类实现高效URL匹配,支持动态参数和类型转换:
@app.route('/post/')
def show_post(post_id):
# post_id自动转换为整数
return f'Post ID: {post_id}'
注入全局变量到所有模板:
@app.context_processor
def inject_user():
return {'current_user': get_current_user()}
扩展模板功能:
@app.template_filter('reverse')
def reverse_filter(s):
return s[::-1]
# 模板中使用:{{ "hello"|reverse }} → "olleh"
Flask支持6种参数类型转换器,确保URL参数的安全性:
类型转换器 | 说明 | 示例 |
string | 默认类型(不含斜杠) | /user/ |
int | 整数参数 | /post/ |
float | 浮点数参数 | /price/ |
path | 包含斜杠的字符串 | /path/ |
uuid | UUID格式字符串 | /file/ |
any | 枚举匹配(需指定允许值) | / |
代码示例:
@app.route('//')
def show_content(category, id):
return f'Category: {category}, ID: {id}'
2.2 请求钩子(Request Hooks)
Flask通过装饰器实现请求处理的生命周期管理:
钩子函数 | 执行时机 | 典型应用场景 |
before_first_request | 首个请求前执行一次 | 初始化数据库连接 |
before_request | 每个请求前执行 | 用户身份验证 |
after_request | 请求处理后执行(需接收响应对象) | 添加HTTP头信息 |
teardown_request | 请求结束后执行(即使有异常) | 清理资源(如关闭文件) |
示例代码:
@app.before_request
def check_auth():
if not hasattr(g, 'user') and request.endpoint != 'login':
return redirect(url_for('login'))
@app.after_request
def add_security_headers(response):
response.headers['X-Content-Type-Options'] = 'nosniff'
return response
{% block header %}{% endblock %}
{% block content %}{% endblock %}
{% block footer %}{% include '_footer.html' %}{% endblock %}
{% extends "base.html" %}
{% block header %}Blog Section
{% endblock %}
使用变量控制继承的块:
{% extends template_name %}
{% block {{ block_name }} %}...{% endblock %}
创建可复用的UI组件:
{% macro input_field(name, label, type='text') %}
{% endmacro %}
{% from "macros/form.html" import input_field %}
{{ input_field('email', 'Email Address', type='email') }}
app.config['WTF_CSRF_ENABLED'] = True
app.config['SECRET_KEY'] = 'your-secret-key'
from flask_wtf.csrf import CSRFProtect
CSRFProtect(app)
from flask_wtf.file import FileField, FileRequired, FileAllowed
class UploadForm(FlaskForm):
file = FileField('PDF文件', validators=[
FileRequired(),
FileAllowed(['pdf'], '仅允许PDF文件')
])
@app.route('/upload', methods=['POST'])
def upload_file():
form = UploadForm()
if form.validate():
f = form.file.data
f.save(os.path.join('uploads', secure_filename(f.filename)))
from wtforms.validators import ValidationError
def validate_username(form, field):
if field.data == 'admin':
raise ValidationError('不能使用保留用户名')
class RegistrationForm(FlaskForm):
username = StringField('用户名', validators=[validate_username])
// 前端实时检查用户名是否可用
$('#username').blur(function() {
$.get('/check_username?q=' + $(this).val(), function(data) {
if (data.exists) {
showError('用户名已存在');
}
});
});
# app/__init__.py
from flask import Flask
from .views import main_bp
def create_app(config_class='config.ProdConfig'):
app = Flask(__name__)
app.config.from_object(config_class)
app.register_blueprint(main_bp)
return app
# app/views/auth.py
from flask import Blueprint
auth_bp = Blueprint('auth', __name__)
@auth_bp.route('/login')
def login():
return render_template('auth/login.html')
配置 gunicorn.conf.py:
workers = 4
worker_class = 'gevent'
bind = '0.0.0.0:8000'
accesslog = '-'
errorlog = '-'
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location /static {
alias /var/www/your_app/static;
expires 30d;
access_log off;
}
}
FROM python:3.9-slim
RUN apt-get update && apt-get install -y nginx
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN chmod +x boot.sh
EXPOSE 80
CMD ["./boot.sh"]
from datetime import datetime
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
posts = db.relationship('Post', backref='author', lazy='dynamic')
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(140))
content = db.Column(db.Text)
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
import markdown
from flask import Markup
@app.template_filter('md')
def markdown_to_html(text):
return Markup(markdown.markdown(text))
from flask_caching import Cache
cache = Cache(config={'CACHE_TYPE': 'RedisCache'})
cache.init_app(app)
@app.route('/feed')
@cache.cached(timeout=300)
def feed():
posts = Post.query.order_by(Post.timestamp.desc()).all()
return render_template('feed.html', posts=posts)
{% cache 300, 'recent_posts' %}
{% for post in recent_posts %}
{{ post.title }}
{% endfor %}
{% endcache %}
安全威胁 | 防护措施 | 实现方式 |
SQL注入 | ORM参数化查询 | SQLAchemy的查询接口 |
XSS攻击 | Jinja2自动转义 | 使用{{ content }}而非 {{ content safe }} |
CSRF攻击 | Flask-WTF集成防护 | 表单中自动添加CSRF Token |
暴力破解 | 登录速率限制 | Flask-Limiter扩展 |
信息泄露 | 生产环境关闭DEBUG模式 | app.config['DEBUG'] = False |
扩展名称 | 功能描述 | 示例场景 |
Flask-SQLAlchemy | ORM数据库集成 | 用户系统、内容管理 |
Flask-Login | 用户会话管理 | 登录状态保持 |
Flask-RESTful | REST API开发 | 移动端后端接口 |
FLask-Mail | 电子邮件支持 | 用户注册验证、通知发送 |
Flask-SocketlO | 实时通信支持 | 在线聊天、实时通知 |