Flask 路由
路由(Routing)是 Web 框架最核心的功能之一,它决定了哪个 URL 由哪个函数处理。
Flask 路由是 Web 应用程序中将 URL 映射到 Python 函数的机制。
Flask 路由是 Flask 应用的核心部分,用于处理不同 URL 的请求,并将请求的处理委托给相应的视图函数。
以下是关于 Flask 路由的详细说明,包括路由的定义、参数、方法和规则等。
基础路由
使用 @app.route() 装饰器将 URL 路径绑定到视图函数:
实例
app = Flask(__name__)
# 绑定根路径 "/"
@app.route("/")
def index():
return "这是首页"
# 绑定 "/hello" 路径
@app.route("/hello")
def hello():
return "Hello, RUNOOB!"
# 不同路径对应不同函数
@app.route("/about")
def about():
return "关于本站"
访问 http://127.0.0.1:5000/hello 时,Flask 调用 hello() 函数。
访问 http://127.0.0.1:5000/about 时,Flask 调用 about() 函数。

变量规则
实际应用中,URL 通常包含动态部分,例如用户 ID、文章标题等。
Flask 使用 <变量名> 语法在 URL 中定义动态部分,对应参数会自动传给视图函数。
字符串变量(默认类型)
不指定类型时,变量默认为字符串,匹配除了斜线 / 以外的任意字符:
实例
@app.route("/user/<username>")
def show_user(username):
# 注意:username 可能包含恶意脚本,实际生产环境需要转义
return f"<h1>用户:{username}</h1>"
# 测试访问:
# /user/runoob → 页面显示 "用户:runoob"
# /user/RUNOOB → 页面显示 "用户:RUNOOB"
类型转换器
Flask 内置了多种转换器,通过 <类型:变量名> 语法指定:
| 转换器 | 说明 | 示例 URL | 匹配结果 |
|---|---|---|---|
| string | 默认,接受不包含 / 的文本 | /user/runoob | username = "runoob" |
| int | 正整数 | /post/42 | post_id = 42 |
| float | 正浮点数 | /price/19.99 | price = 19.99 |
| path | 接受包含 / 的字符串 | /file/a/b/c.txt | filepath = "a/b/c.txt" |
| uuid | UUID 格式字符串 | /item/550e8400-e29b-41d4-a716-446655440000 | item_id = UUID 字符串 |
实例
@app.route("/post/<int:post_id>")
def show_post(post_id):
# post_id 的类型是 int,不是字符串
return f"<h1>文章 #{post_id}</h1>"
# path 转换器:可以匹配包含 / 的路径
@app.route("/file/<path:filepath>")
def show_file(filepath):
return f"<p>文件路径:{filepath}</p>"
# float 转换器:匹配浮点数
@app.route("/price/<float:amount>")
def show_price(amount):
return f"<p>价格:¥{amount}</p>"
# uuid 转换器:只接受标准 UUID 格式
@app.route("/item/<uuid:item_id>")
def show_item(item_id):
return f"<p>商品 ID:{item_id}</p>"
转换器不仅做类型验证,还会自动将匹配的值转换成对应 Python 类型。例如 <int:post_id> 传给视图函数的是 int 而不是 str。
尾斜线的重定向行为
URL 尾部的 / 对路由匹配行为有直接影响,这一点很多初学者会困惑。
实例
# 访问 /projects 会自动 308 重定向到 /projects/
@app.route("/projects/")
def projects():
return "项目列表页面"
# 规则 2:不以 / 结尾——类似文件
# 访问 /about/ 会返回 404 Not Found
@app.route("/about")
def about():
return "关于页面"
| 路由定义 | 访问 /projects | 访问 /projects/ |
|---|---|---|
| @app.route("/projects/") | 308 重定向到 /projects/ | 正常返回 |
| @app.route("/about") | 正常返回 | 404 Not Found |
这个设计对 SEO 有帮助:确保同一内容只有一个标准 URL,避免搜索引擎将同一页面索引两次。
URL 构建——url_for
url_for() 是 Flask 内置的 URL 生成函数,它根据视图函数名生成对应的 URL。
这比硬编码 URL 字符串有很多好处:
- 如果以后修改了 URL 路由,所有通过 url_for 生成的地方自动更新
- 自动处理特殊字符的转义
- 生成的路径始终是绝对路径
实例
app = Flask(__name__)
@app.route("/")
def index():
return "首页"
@app.route("/login")
def login():
return "登录页面"
@app.route("/user/<username>")
def profile(username):
return f"{username} 的个人主页"
# 使用 test_request_context() 来模拟请求上下文
# 这样 url_for() 才能正确生成 URL
with app.test_request_context():
print(url_for("index")) # 输出 /
print(url_for("login")) # 输出 /login
print(url_for("login", next="/")) # 输出 /login?next=%2F
print(url_for("profile", username="runoob")) # 输出 /user/runoob
url_for() 的第一个参数是视图函数名(注意是函数名,不是 URL 路径)。
如果 URL 中包含动态变量,将对应值作为关键字参数传入即可。
多余的未知参数会被自动拼接为查询字符串。
HTTP 方法
默认情况下,路由只响应 GET 请求。
通过 methods 参数可以指定允许的 HTTP 方法:
实例
app = Flask(__name__)
# 同一个 URL 同时响应 GET 和 POST 请求
@app.route("/login", methods=["GET", "POST"])
def login():
# 通过 request.method 判断当前请求类型
if request.method == "POST":
# 处理登录表单提交(POST 请求时执行)
username = request.form.get("username")
return f"<h1>欢迎回来,{username}!</h1>"
else:
# 显示登录表单(GET 请求时执行)
return """
<form method="post">
<input type="text" name="username" placeholder="用户名">
<input type="submit" value="登录">
</form>
"""
快捷方法装饰器
Flask 为常见的 HTTP 方法提供了简写装饰器,让代码更清晰:
实例
@app.get("/login")
def login_form():
return "<form>...</form>"
# 等价于 @app.route("/login", methods=["POST"])
@app.post("/login")
def login_submit():
return "登录成功"
# 还支持 @app.put()、@app.delete()、@app.patch()
@app.delete("/post/<int:post_id>")
def delete_post(post_id):
# 删除文章的 API
return f"文章 {post_id} 已删除"
| 快捷装饰器 | 等价写法 | 典型用途 |
|---|---|---|
| @app.get("/path") | @app.route("/path", methods=["GET"]) | 获取数据、显示页面 |
| @app.post("/path") | @app.route("/path", methods=["POST"]) | 创建数据、提交表单 |
| @app.put("/path") | @app.route("/path", methods=["PUT"]) | 更新数据(完整替换) |
| @app.delete("/path") | @app.route("/path", methods=["DELETE"]) | 删除数据 |
| @app.patch("/path") | @app.route("/path", methods=["PATCH"]) | 更新数据(部分更新) |
自动处理:如果路由定义了 GET 方法,Flask 会自动添加对 HEAD 方法的支持。同时 OPTIONS 方法通常也会被自动处理。
同时绑定多个路由
同一个视图函数可以绑定多个路由:
实例
@app.route("/hello")
@app.route("/hello/<name>")
def greet(name=None):
# name 有默认值 None,当访问 /hello 时 name 为 None
if name is None:
return "<h1>Hello, World!</h1>"
return f"<h1>Hello, {name}!</h1>"
访问 /hello 时 name 取默认值 None,访问 /hello/runoob 时 name 为 "runoob"。
