欢迎光临
我们一直在努力

Flask入门教程(三十一):实用函数与类API——全局工具函数速查

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

赞(0)
未经允许不得转载:171主机测评 » Flask入门教程(三十一):实用函数与类API——全局工具函数速查
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址