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开发中不可或缺的基础组件。