1. 全局代理对象
| current_app | 代理 → Flask | 指向当前活跃的Flask应用实例,在应用上下文中可用 |
from flask import Flask, current_app
app = Flask(__name__)
@app.route("/")
def index():
# 在视图函数中访问应用配置
app_name = current_app.config.get("APP_NAME", "Default")
return f"应用名称: {app_name}"
2. URL和重定向
url_for —— 生成URL
url_for()根据视图函数名生成URL,是Flask中最常用的URL生成工具。
| endpoint | 视图函数名(蓝图需加前缀,如"auth.login") |
| _anchor | URL锚点,如"#section" |
| _method | 指定HTTP方法 |
| _scheme | 协议,如"https" |
| _external | True时生成绝对URL(含域名) |
| **values | URL中的动态变量参数,多余的变为查询字符串 |
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("/posts")
def posts():
return "文章列表"
# 基本用法
with app.test_request_context():
print(url_for("index")) # 输出: /
print(url_for("profile", username="runoob")) # 输出: /user/runoob
print(url_for("posts", page=2)) # 输出: /posts?page=2
# 绝对URL
print(url_for("index", _external=True)) # 输出: http://localhost/ (实际端口可能不同)
# 锚点
print(url_for("posts", _anchor="top")) # 输出: /posts#top
# 蓝图中的用法
# url_for("auth.login") # 蓝图名.视图函数名
redirect —— 重定向
redirect()创建重定向响应,默认状态码为303(See Other)。
| location | 重定向目标URL |
| code | HTTP状态码,默认303 |
| Response | 自定义响应类 |
from flask import Flask, redirect, url_for
app = Flask(__name__)
@app.route("/")
def index():
# 重定向到登录页
return redirect(url_for("login"))
@app.route("/login")
def login():
return "登录页面"
@app.route("/old-page")
def old_page():
# 永久重定向(301)
return redirect(url_for("new_page"), code=301)
@app.route("/new-page")
def new_page():
return "新页面"
# 常用重定向状态码
# 301: 永久移动(SEO友好)
# 302: 临时移动(默认)
# 303: See Other(POST提交后重定向,推荐)
# 307: 临时重定向(保持请求方法不变)
3. 请求终止和响应构建
abort —— 终止请求并返回HTTP错误
abort()立即终止当前请求并返回指定的HTTP错误。
from flask import Flask, abort
app = Flask(__name__)
@app.route("/post/<int:post_id>")
def view_post(post_id):
if post_id < 1 or post_id > 100:
abort(404, description="文章不存在")
return f"文章 #{post_id}"
@app.route("/admin")
def admin():
if not is_admin():
abort(403, description="你没有管理员权限")
return "管理面板"
@app.route("/api/data")
def api_data():
if not request.headers.get("X-API-Key"):
abort(401, description="请提供API密钥")
return {"data": "secret"}
make_response —— 构建响应对象
make_response()将视图返回值转换为Response对象,用于需要精细控制响应的场景。
from flask import Flask, make_response
app = Flask(__name__)
@app.route("/custom")
def custom():
# 方式一:从返回值构建
resp = make_response("<h1>Hello</h1>")
# 方式二:从元组构建
resp = make_response("<h1>Not Found</h1>", 404)
# 方式三:从元组+头构建
resp = make_response("<h1>OK</h1>", 200, {"X-Custom": "value"})
# 设置响应头
resp.headers["X-Powered-By"] = "Flask"
# 设置Cookie
resp.set_cookie("theme", "dark", max_age=3600)
return resp
after_this_request —— 当前请求结束回调
after_this_request注册一个仅在当前请求结束后执行一次的函数(而非全局after_request)。
from flask import Flask, after_this_request, request
app = Flask(__name__)
@app.route("/")
def index():
@after_this_request
def log_response(response):
"""当前请求结束后执行"""
app.logger.info(f"请求 {request.path} 完成,状态码: {response.status_code}")
return response
return "Hello, World!"
4. 上下文检查
| has_request_context() | 返回True如果当前有活跃的请求上下文 |
| has_app_context() | 返回True如果当前有活跃的应用上下文 |
| copy_current_request_context(func) | 装饰器,复制当前请求上下文 |
from flask import Flask, has_request_context, has_app_context, copy_current_request_context
import threading
app = Flask(__name__)
@app.route("/status")
def status():
return {
"has_request_context": has_request_context(),
"has_app_context": has_app_context(),
}
@app.route("/async")
def async_task():
@copy_current_request_context
def background_task():
# 即使在后台线程中,仍可访问 request、g 等
print(f"处理中: {request.path}")
thread = threading.Thread(target=background_task)
thread.start()
return "任务已启动"
5. 文件发送
send_file —— 发送文件
send_file()发送文件内容,支持条件请求和ETag。
from flask import Flask, send_file
import os
app = Flask(__name__)
@app.route("/download/<filename>")
def download_file(filename):
path = os.path.join("uploads", filename)
return send_file(
path,
as_attachment=True, # 触发下载
download_name="report.pdf", # 浏览器显示的文件名
mimetype="application/pdf", # MIME类型
conditional=True, # 支持条件请求(If-Modified-Since等)
etag=True, # 生成ETag
max_age=3600, # 缓存时间(秒)
)
send_from_directory —— 目录安全发送
send_from_directory()从指定目录安全发送文件,使用safe_join防路径遍历攻击。
from flask import Flask, send_from_directory
app = Flask(__name__)
@app.route("/static/<path:filename>")
def custom_static(filename):
# 从指定目录发送文件,自动防止路径遍历
return send_from_directory(
"static_files",
filename,
as_attachment=False, # 浏览器直接显示
)
@app.route("/uploads/<path:filename>")
def uploads(filename):
# 安全发送上传目录中的文件
return send_from_directory(
"uploads",
filename,
as_attachment=True,
download_name=filename,
)
6. 实用函数完整示例
from flask import (
Flask, current_app, url_for, redirect, abort,
make_response, after_this_request,
has_request_context, has_app_context,
send_file, send_from_directory,
request, jsonify
)
import os
import time
app = Flask(__name__)
# ============ 1. current_app ============
@app.route("/app-info")
def app_info():
return {
"app_name": current_app.name,
"debug": current_app.debug,
"config": {k: v for k, v in current_app.config.items() if not k.startswith("_")}
}
# ============ 2. url_for + redirect ============
@app.route("/")
def index():
return f"""
<p><a href="{url_for('profile', username='runoob')}">用户主页</a></p>
<p><a href="{url_for('redirect_me')}">重定向示例</a></p>
"""
@app.route("/profile/<username>")
def profile(username):
return f"<h1>用户: {username}</h1>"
@app.route("/go-home")
def redirect_me():
return redirect(url_for("index"), code=302)
# ============ 3. abort ============
@app.route("/article/<int:article_id>")
def article(article_id):
if article_id < 1:
abort(400, description="文章ID必须大于0")
if article_id > 1000:
abort(404, description="文章不存在")
return f"文章 #{article_id}"
# ============ 4. make_response + after_this_request ============
@app.route("/custom")
def custom_response():
start_time = time.time()
resp = make_response(jsonify({"status": "ok", "data": "RUNOOB"}))
resp.headers["X-Server"] = "Flask"
@after_this_request
def log(response):
duration = time.time() – start_time
app.logger.info(f"请求耗时: {duration:.3f}s")
return response
return resp
# ============ 5. send_file ============
@app.route("/download/<filename>")
def download_file(filename):
# 确保文件存在
filepath = os.path.join("uploads", filename)
if not os.path.exists(filepath):
abort(404, description="文件不存在")
return send_file(
filepath,
as_attachment=True,
download_name=filename,
conditional=True,
)
# ============ 6. send_from_directory ============
@app.route("/static-files/<path:filename>")
def serve_static(filename):
return send_from_directory("static", filename)
# ============ 7. 上下文检查 ============
@app.route("/context-status")
def context_status():
return {
"has_request_context": has_request_context(),
"has_app_context": has_app_context(),
}
7. 实用函数API速查表
| 代理 | current_app | 当前应用实例 |
| URL | url_for(endpoint, **values) | 生成URL |
| 重定向 | redirect(location, code=303) | 创建重定向响应 |
| 错误 | abort(code, description) | 终止请求返回错误 |
| 响应 | make_response(*args) | 构建响应对象 |
| 回调 | after_this_request(func) | 当前请求结束后执行 |
| 上下文 | has_request_context() | 是否有请求上下文 |
| 上下文 | has_app_context() | 是否有应用上下文 |
| 上下文 | copy_current_request_context(func) | 复制请求上下文到新线程 |
| 文件 | send_file(path, **kwargs) | 发送文件 |
| 文件 | send_from_directory(dir, path, **kwargs) | 从目录安全发送文件 |
8. 常见错误与最佳实践
| 在视图函数外使用url_for | 在with app.test_request_context()或视图函数内使用 |
| abort()后继续执行代码 | abort()会抛出异常,后续代码不会执行 |
| 直接拼接文件路径 | 使用send_from_directory防止路径遍历 |
| 忘记处理文件不存在 | 先检查文件是否存在,再send_file |
| 硬编码URL | 使用url_for()动态生成 |
小结
本章全面讲解了Flask的实用函数与类API。current_app是当前应用实例的代理,在应用上下文中可用;url_for()动态生成URL,支持动态变量、查询参数、锚点和绝对URL;redirect()创建重定向响应,支持自定义状态码;abort()立即终止请求返回HTTP错误;make_response()精细构建响应对象;after_this_request注册当前请求结束回调;has_request_context()和has_app_context()检查上下文状态;send_file()和send_from_directory()发送文件,后者自动防止路径遍历攻击。这些工具函数覆盖了Web开发中最常见的需求,是Flask开发中不可或缺的基础组件。





