专题:Python Web开发系统学习
关键词:Python, Web开发, Flask, 路由, @app.route, url_for, 请求响应, session, Flask入门
一、Flask概述
Flask是一个用Python编写的轻量级Web应用框架,由Armin Ronacher在2010年基于Werkzeug工具箱和Jinja2模板引擎构建。它的核心设计哲学是"微框架"——保持核心简洁但具备强大的扩展能力。Flask不强制使用特定的库或项目结构,开发者可以根据需求自由选择组件,这种灵活性使其成为Python Web开发中最受欢迎的框架之一。
核心设计理念
微框架(Microframework):Flask的核心非常精简,仅包含路由、请求/响应处理和模板渲染等最基本的功能。其他功能(如数据库ORM、表单验证、用户认证等)通过扩展实现,开发者按需选用。
显式优于隐式:Flask倾向于让开发者明确地编写代码,而不是通过大量的魔法行为隐藏细节。这使得Flask应用的行为更容易理解和调试。
可扩展性:Flask设计了良好的扩展接口,社区有数百个扩展覆盖了各种常见需求,如Flask-SQLAlchemy(数据库)、Flask-Login(用户认证)、Flask-Mail(邮件发送)等。
Flask vs Django vs FastAPI
| 特性 |
Flask |
Django |
FastAPI |
| 框架类型 |
微框架 |
全栈框架 |
异步框架 |
| 学习曲线 |
平缓 |
较陡 |
中等 |
| 内置功能 |
少(路由+模板) |
全(ORM、Admin、Auth等) |
少(侧重API) |
| 异步支持 |
有限(3.0+开始支持) |
有限(3.0+开始支持) |
原生异步 |
| 自动API文档 |
需扩展 |
需扩展 |
内置(Swagger/ReDoc) |
| 性能 |
中等 |
中等 |
高(基于Starlette) |
| 适用场景 |
中小型项目、微服务、API |
大型项目、CMS、内容站 |
高性能API、实时应用 |
Flask的适用场景
Flask特别适合以下场景:小型到中型Web应用和RESTful API开发;微服务架构中的单个服务;需要快速原型验证的项目;学习和教学场景(代码简洁明了);自定义程度要求高的项目。许多知名公司和项目使用Flask,包括Netflix(内部工具)、Airbnb(部分数据服务)、Reddit(移动API)和Twilio(文档站点)等。
二、Flask安装与Hello World
安装Flask
Flask可以通过pip轻松安装。建议在虚拟环境中进行安装,以避免依赖冲突。
# 创建并激活虚拟环境(推荐)
python -m venv venv
# Windows: venv\Scripts\activate
# macOS/Linux: source venv/bin/activate
# 安装Flask
pip install flask
# 验证安装
python -c "import flask; print(flask.__version__)"
最小Flask应用
创建一个名为 app.py 的文件,只需几行代码即可启动一个Web服务器:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello, World!'
if __name__ == '__main__':
app.run()
运行这个文件:python app.py,然后在浏览器中访问 http://127.0.0.1:5000,就会看到"Hello, World!"字样。
运行方式
Flask应用有两种常见的运行方式:
方式一:直接运行Python文件——在代码末尾调用 app.run(),执行 python app.py 即可启动服务器,默认监听5000端口。
方式二:使用flask命令——设置环境变量后通过 flask run 命令启动:
# 设置Flask应用入口
# Windows (CMD)
set FLASK_APP=app.py
# Windows (PowerShell)
$env:FLASK_APP = "app.py"
# macOS/Linux
export FLASK_APP=app.py
# 启动开发服务器
flask run
调试模式
调试模式是开发过程中非常有用的功能。开启后,代码发生变化时服务器会自动重载,并且在发生异常时会在浏览器中显示详细的错误信息,方便定位问题。
# 方式一:代码中设置
if __name__ == '__main__':
app.run(debug=True)
# 方式二:环境变量设置
# Windows (PowerShell)
$env:FLASK_DEBUG = "1"
# macOS/Linux
export FLASK_DEBUG=1
# 方式三:使用--debug选项(Flask 2.3+)
flask --debug run
重要:调试模式绝不可在生产环境中开启。调试模式下的错误信息会泄露源代码、环境变量等敏感信息,构成严重的安全风险。生产环境应使用成熟的WSGI服务器如Gunicorn或uWSGI。
环境变量配置
Flask支持通过环境变量进行配置,这是12-Factor App推荐的做法:
| 环境变量 |
作用 |
示例 |
| FLASK_APP |
指定应用入口文件 |
FLASK_APP=app.py |
| FLASK_ENV |
指定运行环境(Flask 2.3前) |
FLASK_ENV=development |
| FLASK_DEBUG |
开启/关闭调试模式 |
FLASK_DEBUG=1 |
| FLASK_RUN_HOST |
指定监听地址 |
FLASK_RUN_HOST=0.0.0.0 |
| FLASK_RUN_PORT |
指定监听端口 |
FLASK_RUN_PORT=8080 |
在Flask 2.3及以上版本中,FLASK_ENV 已被弃用,推荐使用 --debug 选项或直接在代码中设置 app.debug = True。
三、路由系统基础
路由是Web框架的核心功能之一。它负责将客户端请求的URL映射到对应的Python处理函数(视图函数)。Flask使用简洁且强大的装饰器语法来实现路由定义。
@app.route()装饰器
在Flask中,使用 @app.route() 装饰器将URL模式与视图函数绑定。当用户访问指定的URL时,Flask会自动调用对应的视图函数,并将返回值作为HTTP响应发送给客户端。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return '这是首页'
@app.route('/about')
def about():
return '关于我们'
@app.route('/contact')
def contact():
return '联系我们'
动态URL
Flask支持在路由中定义动态路径参数,使用尖括号 <variable> 语法。Flask会自动从URL中提取对应的值,并作为参数传递给视图函数。你还可以指定参数的类型转换器,自动完成类型转换和验证。
from flask import Flask
app = Flask(__name__)
# 默认字符串类型(不含斜杠)
@app.route('/user/<username>')
def user_profile(username):
return f'用户:{username}'
# int类型转换器
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'文章编号:{post_id}(类型:{type(post_id).__name__})'
# float类型转换器
@app.route('/product/<float:price>')
def show_price(price):
return f'商品价格:{price}'
# path类型转换器(可以包含斜杠)
@app.route('/path/<path:subpath>')
def show_path(subpath):
return f'子路径:{subpath}'
Flask内置的类型转换器及其行为:
| 转换器 |
说明 |
匹配示例 |
| string |
默认类型,匹配任意不含斜杠的字符串 |
/user/john |
| int |
匹配正整数,自动转换为int类型 |
/post/42 |
| float |
匹配浮点数,自动转换为float类型 |
/price/19.99 |
| path |
类似string但可包含斜杠 |
/path/a/b/c |
| uuid |
匹配UUID格式字符串 |
/item/550e8400-e29b-...} |
HTTP方法限定
默认情况下,路由只响应GET请求。通过 methods 参数可以指定视图函数支持的HTTP方法。这在构建RESTful API时尤为重要。
from flask import Flask, request
app = Flask(__name__)
@app.route('/api/users', methods=['GET', 'POST'])
def users():
if request.method == 'GET':
return '获取用户列表'
elif request.method == 'POST':
return '创建新用户'
@app.route('/api/users/<int:user_id>', methods=['GET', 'PUT', 'DELETE'])
def user_detail(user_id):
if request.method == 'GET':
return f'获取用户{user_id}详情'
elif request.method == 'PUT':
return f'更新用户{user_id}信息'
elif request.method == 'DELETE':
return f'删除用户{user_id}'
同一个视图多个路由
一个视图函数可以绑定多个URL路由,这对于处理别名或兼容旧版URL非常有用:
from flask import Flask
app = Flask(__name__)
@app.route('/')
@app.route('/index')
@app.route('/home')
def home():
return '欢迎访问首页'
@app.route('/profile')
@app.route('/user/<username>')
def profile(username=None):
if username:
return f'用户:{username}的页面'
return '个人中心页面'
要点:路由的顺序很重要。Flask按路由定义的顺序依次匹配URL。如果某个路由模式可能匹配更广泛的URL,应在更具体的路由之前定义。例如 /user/<username> 应定义在 /user/admin 之前——但实际上更具体的字面路径会优先匹配,Flask的路由匹配机制会正确处理这一情况。
四、URL构建与重定向
Flask提供了一系列实用函数用于URL生成和页面跳转,这些函数是构建可维护Web应用的重要工具。
url_for()函数
url_for() 是Flask中最强大的函数之一。它根据视图函数的端点名(endpoint)生成对应的URL。使用 url_for() 而不是在代码中硬编码URL,可以带来几个重要好处:URL修改时只需改路由定义,代码中不需要做任何调整;自动处理URL中的特殊字符转义;支持生成带查询参数的URL;与蓝图(Blueprint)良好集成。
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/')
def index():
return '首页'
@app.route('/user/<username>')
def profile(username):
return f'用户:{username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'文章:{post_id}'
# 在另一个视图中使用url_for
@app.route('/nav')
def navigation():
# 生成静态URL
index_url = url_for('index')
# 生成动态URL(传入参数)
profile_url = url_for('profile', username='john')
post_url = url_for('show_post', post_id=42)
# 生成带查询参数的URL
search_url = url_for('index', q='flask', page=1)
return f'''
<a href="{index_url}">首页</a><br>
<a href="{profile_url}">John的主页</a><br>
<a href="{post_url}">文章42</a><br>
<a href="{search_url}">搜索Flask</a>
'''
执行 url_for('profile', username='john') 会生成 /user/john;url_for('show_post', post_id=42) 生成 /post/42;添加额外的关键字参数(如 q='flask')会自动转为查询字符串。
静态文件URL
Flask会自动为放置在 static/ 目录下的静态文件提供访问服务。使用 url_for() 生成静态文件URL是最佳实践:
# 在Python代码中
css_url = url_for('static', filename='css/style.css')
js_url = url_for('static', filename='js/app.js')
img_url = url_for('static', filename='images/logo.png')
{# 在Jinja2模板中 #}
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">
redirect()重定向
redirect() 函数用于将用户重定向到另一个URL,常用于表单提交后跳转、登录后跳转到原页面等场景。通常与 url_for() 配合使用:
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route('/')
def index():
return '首页'
@app.route('/old-page')
def old_page():
# 旧页面重定向到新页面
return redirect(url_for('new_page'))
@app.route('/new-page')
def new_page():
return '这是新页面!'
@app.route('/login')
def login():
return '登录页面(此处应有登录表单)'
@app.route('/dashboard')
def dashboard():
# 模拟登录成功后重定向
return redirect(url_for('dashboard_home'))
@app.route('/dashboard/home')
def dashboard_home():
return '欢迎进入控制面板'
redirect() 默认返回302状态码(临时重定向)。如果需要301(永久重定向)或其他状态码,可以通过第二个参数指定:redirect(url_for('new_page'), code=301)。
abort()错误终止
abort() 函数用于立即终止请求并返回指定的HTTP错误状态码。它通常用于权限检查、资源不存在等场景:
from flask import Flask, abort
app = Flask(__name__)
@app.route('/admin')
def admin():
# 模拟权限检查
abort(403) # 禁止访问
@app.route('/item/<int:item_id>')
def get_item(item_id):
items = {1: '苹果', 2: '香蕉', 3: '橙子'}
if item_id not in items:
abort(404) # 资源不存在
return items[item_id]
# 自定义错误处理
@app.errorhandler(404)
def not_found(error):
return '页面未找到,请检查URL是否正确', 404
@app.errorhandler(403)
def forbidden(error):
return '您没有权限访问此页面', 403
@app.errorhandler(500)
def internal_error(error):
return '服务器内部错误,请联系管理员', 500
五、请求对象(request)
Flask的 request 对象封装了客户端发送的所有HTTP请求信息。它是一个全局可访问的对象,但实际上是线程安全的——Flask使用线程本地(thread local)机制确保每个请求都有自己的独立数据。理解 request 对象的各个属性是编写Web应用的基础。
request.method:请求方法
获取当前请求的HTTP方法(GET、POST、PUT、DELETE等),常用于在同一个视图函数中处理不同的请求方法:
@app.route('/form', methods=['GET', 'POST'])
def form_page():
if request.method == 'POST':
return '收到POST请求'
return '这是GET请求,显示表单'
request.args:GET查询参数
获取URL中的查询字符串参数(即 ?key=value 部分)。返回一个类似字典的不可变对象:
from flask import Flask, request
app = Flask(__name__)
@app.route('/search')
def search():
query = request.args.get('q', '') # 获取q参数,默认为空字符串
page = request.args.get('page', 1, type=int) # 自动转为int类型
size = request.args.get('size', 10, type=int)
# 访问 /search?q=flask&page=2&size=20
return f'搜索:{query},第{page}页,每页{size}条'
@app.route('/multi')
def multi_args():
# 获取所有名为tag的参数值
# URL: /multi?tag=python&tag=flask&tag=web
tags = request.args.getlist('tag')
return f'标签:{", ".join(tags)}'
request.form:POST表单数据
获取通过POST方法提交的表单数据。当请求的Content-Type为 application/x-www-form-urlencoded 或 multipart/form-data 时使用:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
# 验证用户名和密码...
return f'登录尝试:{username}'
return '''
<form method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<button type="submit">登录</button>
</form>
'''
request.json:JSON数据
自动解析Content-Type为 application/json 的请求体。如果请求体不是合法JSON,则 request.json 为 None。注意 request.get_json() 方法提供了更多的控制选项:
from flask import Flask, request, jsonify
app = Flask(__name__)
@app.route('/api/data', methods=['POST'])
def receive_json():
# 方式一:直接访问属性
data = request.json
if not data:
return jsonify({'error': '请提供有效的JSON数据'}), 400
# 方式二:使用方法(更推荐,可传入参数)
# data = request.get_json(force=True) # force=True:即使Content-Type不是application/json也解析
# data = request.get_json(silent=True) # silent=True:解析失败返回None而不是抛出异常
name = data.get('name')
age = data.get('age')
return jsonify({'message': f'收到:{name},年龄{age}'})
request.headers:请求头
获取HTTP请求头信息,常用于获取认证令牌、浏览器信息、自定义头等:
@app.route('/headers')
def show_headers():
# 获取User-Agent
user_agent = request.headers.get('User-Agent')
# 获取认证令牌
auth_token = request.headers.get('Authorization')
# 获取自定义头
x_request_id = request.headers.get('X-Request-Id')
return f'''
浏览器:{user_agent}<br>
认证令牌:{auth_token[:20] if auth_token else "无"}<br>
请求ID:{x_request_id or "无"}
'''
request.files:上传文件
处理通过表单上传的文件。文件对象是 FileStorage 实例,提供 save()、filename、read() 等方法:
import os
from flask import Flask, request
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 限制上传大小为16MB
@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
return '没有文件部分'
file = request.files['file']
if file.filename == '':
return '没有选择文件'
if file:
# 保存文件
filename = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
file.save(filename)
return f'文件上传成功:{file.filename}(大小:{os.path.getsize(filename)}字节)'
return '''
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
'''
request.cookies:Cookie
获取客户端发送的Cookie数据:
@app.route('/check-cookie')
def check_cookie():
username = request.cookies.get('username')
last_visit = request.cookies.get('last_visit')
if username:
return f'欢迎回来,{username}!上次访问:{last_visit}'
return '这是您第一次访问'
提示:使用 request.args.get(key, default, type) 的 type 参数可以自动进行类型转换,如 request.args.get('page', 1, type=int)。如果转换失败,则返回默认值而不是引发异常,这在处理用户输入时非常安全。
六、响应对象
Flask视图函数的返回值会被自动转换为HTTP响应对象。Flask提供了多种方式来构建和定制响应,以满足不同的应用场景。
返回字符串
最简单的响应形式,直接返回字符串。Flask会自动将其包装为 Response 对象,并设置Content-Type为 text/html(默认)或 text/plain:
@app.route('/string')
def string_response():
return 'Hello, Flask!' # 自动转为Response对象,状态码200
@app.route('/tuple')
def tuple_response():
# 返回(响应体, 状态码, 响应头)元组
return '创建成功', 201, {'X-Custom-Header': 'custom-value'}
@app.route('/plain')
def plain_response():
return '纯文本响应', 200, {'Content-Type': 'text/plain; charset=utf-8'}
返回模板(render_template)
使用Jinja2模板引擎渲染HTML页面。默认会在 templates/ 目录下查找模板文件。模板支持变量插值、过滤器、控制结构、模板继承等强大功能:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', title='首页', name='Flask')
@app.route('/user/<username>')
def user_page(username):
user = {'name': username, 'age': 25, 'bio': 'Python开发者'}
posts = ['Flask入门指南', '路由系统详解', '请求与响应']
return render_template('user.html', user=user, posts=posts)
{# templates/user.html #}
<!DOCTYPE html>
<html>
<head>
<title>{{ user.name }}的个人主页</title>
</head>
<body>
<h1>{{ user.name }}</h1>
<p>年龄:{{ user.age }}</p>
<p>简介:{{ user.bio }}</p>
<h2>文章列表</h2>
<ul>
{% for post in posts %}
<li>{{ post }}</li>
{% endfor %}
</ul>
</body>
</html>
返回JSON(jsonify)
构建RESTful API时,jsonify() 是最常用的响应方式。它会自动设置Content-Type为 application/json,并对数据进行JSON序列化。Flask 2.3+中,你也可以直接返回字典,Flask会自动调用 jsonify():
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/user/<int:user_id>')
def get_user(user_id):
user = {
'id': user_id,
'name': '张三',
'email': 'zhangsan@example.com',
'age': 28,
'skills': ['Python', 'Flask', 'JavaScript']
}
return jsonify(user)
@app.route('/api/users')
def get_users():
users = [
{'id': 1, 'name': '张三'},
{'id': 2, 'name': '李四'},
{'id': 3, 'name': '王五'}
]
return jsonify({
'code': 200,
'message': 'success',
'data': users,
'total': len(users)
})
# Flask 2.3+ 可以直接返回字典(自动调用jsonify)
@app.route('/api/status')
def api_status():
return {'status': 'ok', 'version': '1.0.0'}
自定义响应状态码和头
有时需要自定义HTTP状态码和响应头,可以返回元组或使用 make_response():
@app.route('/api/data')
def custom_response():
data = {'message': '操作成功'}
# 方式一:返回元组
# return jsonify(data), 201
# 方式二:返回元组(含自定义头)
# return jsonify(data), 201, {'X-RateLimit-Remaining': '100'}
# 方式三:使用make_response(最灵活)
response = jsonify(data)
response.status_code = 201
response.headers['X-RateLimit-Remaining'] = '100'
response.headers['X-RateLimit-Reset'] = '3600'
response.content_type = 'application/json; charset=utf-8'
return response
make_response()创建响应
make_response() 是一个底层工具函数,可以构建完全自定义的响应对象:
from flask import Flask, make_response
app = Flask(__name__)
@app.route('/download')
def download_file():
content = '这是要下载的文件内容'
response = make_response(content)
response.headers['Content-Type'] = 'text/plain; charset=utf-8'
response.headers['Content-Disposition'] = 'attachment; filename=readme.txt'
return response
@app.route('/xml')
def xml_response():
xml_content = '''<?xml version="1.0"?>
<response>
<status>success</status>
<message>Hello XML</message>
</response>'''
response = make_response(xml_content)
response.content_type = 'application/xml'
return response
响应对象属性
Response 对象的常用属性和方法:
| 属性/方法 |
说明 |
示例 |
| status_code |
HTTP状态码 |
response.status_code = 404 |
| status |
状态码+原因短语 |
response.status = '404 Not Found' |
| headers |
响应头字典 |
response.headers['X-Custom'] = 'val' |
| content_type |
Content-Type头 |
response.content_type = 'application/json' |
| set_cookie() |
设置Cookie |
response.set_cookie('key', 'value') |
| delete_cookie() |
删除Cookie |
response.delete_cookie('key') |
| data |
响应体数据(字节串) |
response.data 获取字节内容 |
七、会话与Cookie
HTTP是无状态协议,服务器默认无法识别多个请求是否来自同一个用户。Cookie和Session是解决这一问题的两种常用机制。Flask提供了内置的支持,使状态管理变得简单而安全。
session对象
Flask的 session 对象提供了一种在请求之间存储用户特定数据的机制。与直接使用Cookie不同,Flask的session数据经过加密签名后存储在客户端(浏览器)的Cookie中,因此不需要服务器端存储。这意味着默认不依赖外部缓存或数据库即可实现会话管理。
session的工作流程:用户首次访问时,Flask创建一个包含加密数据的Cookie;用户发送请求时,Flask验证Cookie的签名,解密后加载到 session 对象中;视图函数可以像操作字典一样读写session数据。
app.secret_key设置
secret_key 是Flask应用的必需配置项,用于对session数据进行加密签名,防止数据被篡改。必须设置为一个足够长且复杂的随机字符串,并且绝不应该泄露:
import os
from flask import Flask, session
app = Flask(__name__)
# 方式一:直接设置(不推荐,不宜硬编码)
app.secret_key = '你的密钥字符串'
# 方式二:从环境变量读取(推荐)
app.secret_key = os.environ.get('SECRET_KEY', '开发环境备用密钥')
# 方式三:生成随机密钥(每次重启都会变化,不适合生产)
app.secret_key = os.urandom(24)
# 方式四:从配置文件读取(推荐生产环境)
# app.config.from_pyfile('config.py')
# app.config.from_object('config.Config')
存储和读取session数据
session 对象的用法与Python字典几乎完全一致。在视图函数中可以方便地读写session数据,这些数据会在请求之间持久保存:
from flask import Flask, session, redirect, url_for, request
app = Flask(__name__)
app.secret_key = 'your-secret-key-here'
@app.route('/')
def index():
if 'username' in session:
return f'已登录用户:{session["username"]},角色:{session.get("role", "普通用户")}'
return '未登录,请访问 /login 登录'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 存储到session
session['username'] = request.form['username']
session['role'] = 'user'
session['login_time'] = '2026-05-05 23:13:25'
session['is_authenticated'] = True
return redirect(url_for('index'))
return '''
<form method="post">
<input type="text" name="username" placeholder="用户名">
<button type="submit">登录</button>
</form>
'''
@app.route('/logout')
def logout():
# 删除特定键
session.pop('username', None)
# 或清空整个session
session.clear()
return redirect(url_for('index'))
@app.route('/profile')
def profile():
# 获取session中的所有数据
user_data = dict(session)
return str(user_data)
安全提醒:Flask默认的session数据存储在客户端Cookie中,大小限制为4KB。数据是经过签名但并未加密的(使用itsdangerous库),用户可以看到数据内容但无法篡改。因此绝对不要在session中存储密码、信用卡号等敏感信息。如果需要存储敏感数据,可以使用Flask-Session扩展将session数据存储在服务器端(Redis、数据库等),Cookie中仅保存一个会话ID。
设置和清除Cookie
Cookie是直接由服务器设置并存储在客户端的键值对。Flask通过响应对象的 set_cookie() 和 delete_cookie() 方法管理Cookie:
from flask import Flask, request, make_response
from datetime import datetime, timedelta
app = Flask(__name__)
@app.route('/set-cookie')
def set_cookie():
resp = make_response('Cookie已设置')
# 基本Cookie设置
resp.set_cookie('username', 'zhangsan')
# 带过期时间的Cookie(7天后过期)
resp.set_cookie('theme', 'dark', max_age=7*24*60*60)
# 指定过期日期
expires = datetime.now() + timedelta(days=30)
resp.set_cookie('preference', 'zh-CN', expires=expires)
# 设置安全相关属性
resp.set_cookie('session_id', 'abc123',
max_age=3600, # 1小时后过期
httponly=True, # 禁止JavaScript访问(防XSS)
secure=True, # 仅通过HTTPS传输
samesite='Lax') # 防止CSRF攻击
# 设置路径限定Cookie
resp.set_cookie('admin_token', 'token_value', path='/admin')
return resp
@app.route('/get-cookie')
def get_cookie():
username = request.cookies.get('username')
theme = request.cookies.get('theme')
return f'用户名:{username},主题:{theme}'
@app.route('/delete-cookie')
def delete_cookie():
resp = make_response('Cookie已删除')
resp.delete_cookie('username')
resp.delete_cookie('theme')
# 如果设置了path参数,删除时需指定同样的path
resp.delete_cookie('admin_token', path='/admin')
return resp
@app.route('/all-cookies')
def all_cookies():
# 获取所有Cookie
cookies = dict(request.cookies)
return str(cookies)
Cookie常用参数详解:
| 参数 |
类型 |
说明 |
| key |
str |
Cookie的名称 |
| value |
str |
Cookie的值 |
| max_age |
int |
过期时间(秒)。设为None则Cookie在浏览器关闭时失效 |
| expires |
datetime |
过期日期(替代max_age的旧方式) |
| path |
str |
Cookie有效的URL路径,默认当前路径 |
| domain |
str |
Cookie有效的域名,默认当前域名 |
| secure |
bool |
是否仅通过HTTPS传输 |
| httponly |
bool |
禁止JavaScript读取Cookie(防止XSS攻击) |
| samesite |
str |
限制跨站请求时发送Cookie(Strict/Lax/None),防止CSRF攻击 |
总结:Flask的session和Cookie机制为Web应用提供了灵活的状态管理方案。session适合存储用户登录状态、偏好设置等结构化数据;Cookie适合存储客户端追踪标识、语言偏好等简单数据。两者结合使用,可以构建功能完善且安全的用户状态管理系统。在实际生产中,建议将session存储在Redis等后端服务中(通过Flask-Session扩展),以支持水平扩展和跨服务器会话共享。