现在位置: 首页 > Flask 教程 > 正文

Flask 路由

路由(Routing)是 Web 框架最核心的功能之一,它决定了哪个 URL 由哪个函数处理。

Flask 路由是 Web 应用程序中将 URL 映射到 Python 函数的机制。

Flask 路由是 Flask 应用的核心部分,用于处理不同 URL 的请求,并将请求的处理委托给相应的视图函数。

以下是关于 Flask 路由的详细说明,包括路由的定义、参数、方法和规则等。


基础路由

使用 @app.route() 装饰器将 URL 路径绑定到视图函数:

实例

from flask import Flask

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 中定义动态部分,对应参数会自动传给视图函数。

字符串变量(默认类型)

不指定类型时,变量默认为字符串,匹配除了斜线 / 以外的任意字符:

实例

# <username> 是动态变量,Flask 将其值作为 keyword 参数传递给视图函数
@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 字符串

实例

# int 转换器:只有数字才能匹配,/post/abc 会返回 404
@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 尾部的 / 对路由匹配行为有直接影响,这一点很多初学者会困惑。

实例

# 规则 1:以 / 结尾——类似目录
# 访问 /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 生成的地方自动更新
  • 自动处理特殊字符的转义
  • 生成的路径始终是绝对路径

实例

from flask import Flask, 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 方法:

实例

from flask import Flask, request

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.route("/login", methods=["GET"])
@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 方法通常也会被自动处理。


同时绑定多个路由

同一个视图函数可以绑定多个路由:

实例

# 两个不同的 URL 指向同一个视图函数
@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>"

访问 /helloname 取默认值 None,访问 /hello/runoobname"runoob"