Flask入门学习教程,从入门到精通, 认识Flask路由 — 知识点详解 (2)

路由 --- 知识点详解


一、注册路由

1.1 路由的概念

路由(Route)是指 URL 与视图函数之间的映射关系。当用户访问某个 URL 时,Flask 会根据路由表找到对应的视图函数来处理请求并返回响应。

1.2 注册路由的方式

方式一:使用 @app.route() 装饰器

python 复制代码
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return '首页'

@app.route('/hello')
def hello():
    return 'Hello, Flask!'

方式二:使用 app.add_url_rule() 方法

python 复制代码
def index():
    return '首页'

app.add_url_rule('/', view_func=index, endpoint='index')

1.3 app.route() 底层原理

@app.route('/') 装饰器本质上是调用了 app.add_url_rule() 方法,执行以下三步:

  1. 将 URL 规则(rule)和视图函数(view_func)的映射关系保存到 app.url_map
  2. 为视图函数设置一个端点名(endpoint),默认为函数名
  3. 返回被装饰的视图函数本身

1.4 endpoint(端点)

  • 每个路由规则都有一个唯一的 endpoint 标识
  • 默认情况下,endpoint 就是视图函数的函数名
  • 可以通过 endpoint 参数自定义:
python 复制代码
@app.route('/user', endpoint='user_profile')
def user():
    return '用户页面'
  • 作用 :endpoint 用于 URL 反向解析,通过 url_for() 根据端点名生成 URL

1.5 路由注册注意事项

  • 同一个 URL 不能注册多个视图函数(endpoint 不能重复)
  • 同一个视图函数可以注册多个 URL
  • URL 规则默认以 / 开头
python 复制代码
# 同一个函数绑定多个URL
@app.route('/')
@app.route('/index')
def index():
    return '首页'

二、URL 传递参数

2.1 URL 参数的概念

URL 中可以携带动态参数,Flask 会将 URL 中的可变部分提取出来,作为参数传递给视图函数。

2.2 URL 传递参数的方式

方式一:在 URL 规则中使用变量规则(路径参数)

python 复制代码
@app.route('/user/<username>')
def show_user(username):
    return f'用户:{username}'

访问 /user/zhangsanusername 的值为 'zhangsan'

方式二:使用查询字符串(Query String)

python 复制代码
from flask import request

@app.route('/search')
def search():
    keyword = request.args.get('keyword', '')
    return f'搜索关键词:{keyword}'

访问 /search?keyword=flask,通过 request.args 获取参数

2.3 两种方式的对比

特性 路径参数 查询字符串
语法 <variable> ?key=value
获取方式 视图函数参数 request.args.get()
适用场景 资源标识(如用户ID) 筛选、搜索、分页
是否必须 是(缺少则404) 否(可选参数)
示例URL /user/123 /search?q=flask&page=1

三、为参数指定转换器

3.1 转换器的概念

转换器(Converter)用于对 URL 中的变量进行类型验证和转换,确保传入视图函数的参数是预期的类型。

3.2 内置转换器

转换器 说明 示例 匹配示例
string 默认转换器,匹配任意不含斜杠的字符串 <string:name> /user/tomname='tom'
int 匹配正整数 <int:user_id> /user/123user_id=123
float 匹配正浮点数 <float:price> /price/9.99price=9.99
path 类似 string,但可以包含斜杠 <path:filepath> /file/a/b/c.txtfilepath='a/b/c.txt'
uuid 匹配 UUID 字符串 <uuid:id> /item/123e4567-e89b-12d3-a456-426614174000
any 匹配多个可选值中的任意一个 <any(apple,banana):fruit> /fruit/apple/fruit/banana

3.3 使用示例

python 复制代码
@app.route('/user/<int:user_id>')
def get_user(user_id):
    # user_id 自动转为 int 类型
    return f'用户ID:{user_id},类型:{type(user_id).__name__}'

@app.route('/path/<path:subpath>')
def show_subpath(subpath):
    return f'子路径:{subpath}'

@app.route('/color/<any(red, green, blue):color>')
def color_page(color):
    return f'颜色:{color}'

3.4 自定义转换器

当内置转换器不满足需求时,可以自定义转换器:

python 复制代码
from werkzeug.routing import BaseConverter

class RegexConverter(BaseConverter):
    """自定义正则转换器"""
    def __init__(self, url_map, *items):
        super().__init__(url_map)
        self.regex = items[0]  # 第一个参数作为正则表达式

# 注册自定义转换器
app.url_map.converters['regex'] = RegexConverter

@app.route('/phone/<regex("1[3-9]\\d{9}"):phone_number>')
def show_phone(phone_number):
    return f'手机号:{phone_number}'

自定义转换器需要继承 werkzeug.routing.BaseConverter,并实现以下属性/方法:

  • regex 属性:定义匹配规则的正则表达式
  • to_python() 方法:将 URL 中的字符串转换为 Python 对象
  • to_url() 方法:将 Python 对象转换为 URL 中的字符串(用于反向解析)
python 复制代码
class ListConverter(BaseConverter):
    def to_python(self, value):
        return value.split('+')

    def to_url(self, value):
        return '+'.join(value)

app.url_map.converters['list'] = ListConverter

@app.route('/tags/<list:tags>')
def show_tags(tags):
    return f'Tags: {tags}'  # tags 是一个列表

四、处理请求

4.1 Request 对象

Flask 通过 request 对象封装了客户端发送的 HTTP 请求信息。使用前需导入:

python 复制代码
from flask import request

4.2 Request 对象常用属性

属性/方法 说明 示例
request.method 请求方法(GET/POST等) 'GET''POST'
request.url 完整的请求 URL 'http://example.com/path?q=1'
request.base_url 不含查询字符串的 URL 'http://example.com/path'
request.host 主机名(含端口) 'example.com:5000'
request.path 请求路径 '/path'
request.full_path 路径+查询字符串 '/path?q=1'
request.args 查询字符串参数(ImmutableMultiDict) request.args.get('q')
request.form 表单数据(POST请求) request.form.get('username')
request.data 未解析的原始请求体数据 b'raw data'
request.json JSON 格式的请求体(Content-Type为application/json) {'key': 'value'}
request.values 合并 args 和 form request.values.get('key')
request.headers 请求头 request.headers.get('User-Agent')
request.cookies Cookie 字典 request.cookies.get('session_id')
request.files 上传的文件 request.files['avatar']
request.remote_addr 客户端 IP 地址 '127.0.0.1'

4.3 获取查询字符串参数

python 复制代码
@app.route('/search')
def search():
    # 获取单个参数,第二个参数为默认值
    keyword = request.args.get('keyword', '')
    page = request.args.get('page', 1, type=int)

    # 获取同名参数的多个值
    tags = request.args.getlist('tags')  # /search?tags=python&tags=flask
    return f'keyword={keyword}, page={page}, tags={tags}'

4.4 获取表单数据

python 复制代码
@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    return f'登录用户:{username}'

4.5 获取 JSON 数据

python 复制代码
@app.route('/api/data', methods=['POST'])
def receive_data():
    data = request.get_json()  # 或 request.json
    name = data.get('name')
    return f'收到数据:{name}'

4.6 文件上传

python 复制代码
from flask import request
from werkzeug.utils import secure_filename

@app.route('/upload', methods=['POST'])
def upload():
    f = request.files['file']
    if f:
        filename = secure_filename(f.filename)  # 安全处理文件名
        f.save(f'uploads/{filename}')
        return '上传成功'
    return '未选择文件'

五、指定请求方式

5.1 HTTP 请求方法

方法 说明 典型用途
GET 获取资源 查看页面、获取数据
POST 提交数据 提交表单、上传文件
PUT 更新资源(完整替换) 更新用户信息
PATCH 部分更新资源 修改部分字段
DELETE 删除资源 删除记录
HEAD 获取响应头(不返回body) 检查资源是否存在
OPTIONS 获取支持的请求方法 CORS 预检请求

5.2 指定请求方式

Flask 路由默认只响应 GET 请求。通过 methods 参数指定允许的请求方法:

python 复制代码
@app.route('/user', methods=['GET', 'POST'])
def user():
    if request.method == 'GET':
        return '获取用户列表'
    elif request.method == 'POST':
        return '创建新用户'

5.3 使用单独的装饰器

python 复制代码
@app.route('/user', methods=['GET'])
def get_users():
    return '用户列表'

@app.route('/user', methods=['POST'])
def create_user():
    return '创建用户'

注意 :以上写法 endpoint 会冲突(都是 get_userscreate_user 的函数名不同但绑定在同一 URL 上,Flask 会正常处理,因为它们的 endpoint 不同)。

5.4 RESTful 风格示例

python 复制代码
@app.route('/api/articles', methods=['GET'])
def list_articles():
    return '文章列表'

@app.route('/api/articles', methods=['POST'])
def create_article():
    return '创建文章'

@app.route('/api/articles/<int:article_id>', methods=['GET'])
def get_article(article_id):
    return f'文章详情:{article_id}'

@app.route('/api/articles/<int:article_id>', methods=['PUT'])
def update_article(article_id):
    return f'更新文章:{article_id}'

@app.route('/api/articles/<int:article_id>', methods=['DELETE'])
def delete_article(article_id):
    return f'删除文章:{article_id}'

六、请求钩子

6.1 请求钩子的概念

请求钩子(Hook)是在请求处理的不同阶段执行的函数。通过装饰器注册,可以在请求前、响应后等阶段执行通用逻辑(如数据库连接、身份认证、日志记录等)。

6.2 四种请求钩子

钩子 装饰器 执行时机 典型用途
before_first_request @app.before_first_request 第一个请求到达前执行一次 初始化操作(已废弃于Flask 2.3)
before_request @app.before_request 每个请求到达视图函数前执行 身份验证、数据库连接、权限检查
after_request @app.after_request 每个请求执行视图函数后、响应返回前执行 修改响应、设置响应头、日志记录
teardown_request @app.teardown_request 每个请求结束后执行(即使发生异常) 清理资源、关闭数据库连接

此外还有应用级别的:

  • before_first_request → 应用级别(已废弃)
  • teardown_appcontext → 应用上下文销毁时执行

6.3 钩子的使用示例

python 复制代码
from flask import Flask, request, g
import time

app = Flask(__name__)

# before_request:每个请求前执行
@app.before_request
def before_request_func():
    # 记录请求开始时间
    g.start_time = time.time()
    # 身份验证检查
    if request.endpoint not in ('login', 'register'):
        token = request.headers.get('Authorization')
        if not token:
            return '未授权访问', 401

# after_request:每个请求后执行
@app.after_request
def after_request_func(response):
    # 添加自定义响应头
    response.headers['X-Custom-Header'] = 'FlaskApp'
    # 计算请求耗时
    if hasattr(g, 'start_time'):
        elapsed = time.time() - g.start_time
        response.headers['X-Response-Time'] = f'{elapsed:.4f}s'
    return response  # 必须返回 response 对象

# teardown_request:请求结束后执行(即使出错也会执行)
@app.teardown_request
def teardown_request_func(exception):
    if exception:
        app.logger.error(f'请求异常:{exception}')
    # 清理资源

6.4 钩子执行顺序

复制代码
请求进入
  → before_request(按注册顺序)
    → 视图函数执行
  → after_request(按注册的**逆序**)
响应返回
  → teardown_request(按注册的**逆序**)

6.5 before_request 中止请求

如果 before_request 返回了非 None 的响应对象,后续的 before_request 和视图函数将不会执行,该响应会直接作为最终响应返回:

python 复制代码
@app.before_request
def check_maintenance():
    if app.config.get('MAINTENANCE_MODE'):
        return '系统维护中,请稍后再试', 503

七、上下文

7.1 上下文的概念

上下文(Context)是 Flask 中一个核心概念,用于在特定环境中临时提供某些全局可访问的对象。Flask 使用上下文机制来确保线程安全。

7.2 两种上下文

7.2.1 应用上下文(Application Context)
对象 说明
current_app 当前应用实例,用于访问应用配置、日志等
g 临时存储对象,在一次请求周期内存储数据
7.2.2 请求上下文(Request Context)
对象 说明
request 封装客户端 HTTP 请求信息
session 用户会话,基于 Cookie 实现,存储键值对数据

7.3 上下文对象的生命周期

对象 创建时机 销毁时机
request 请求到达时 响应返回后
session 请求到达时(从Cookie解析) 响应返回后(写入Cookie)
current_app 推入应用上下文时 弹出应用上下文时
g 推入应用上下文时 应用上下文销毁时

7.4 g 对象

g(global 的缩写)是存储请求级别数据的容器,在整个请求处理过程中可访问,请求结束后自动销毁:

python 复制代码
from flask import g

@app.before_request
def load_user():
    g.db = connect_database()  # 在 g 上存储数据库连接
    g.user = get_current_user()  # 在 g 上存储当前用户

@app.route('/profile')
def profile():
    user = g.user  # 在视图函数中访问
    db = g.db
    return f'用户:{user.name}'

@app.teardown_request
def close_db(exception):
    db = g.pop('db', None)
    if db:
        db.close()

7.5 session 对象

python 复制代码
from flask import session

app.secret_key = 'your-secret-key'  # 必须设置密钥

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    session['username'] = username  # 存储到session
    session.permanent = True  # 设置持久化
    return '登录成功'

@app.route('/profile')
def profile():
    username = session.get('username')  # 从session读取
    if username:
        return f'欢迎,{username}'
    return '请先登录'

@app.route('/logout')
def logout():
    session.pop('username', None)  # 清除session
    return '已退出登录'

7.6 上下文的工作原理

Flask 使用 上下文栈(Context Stack)来管理上下文:

  1. 当请求到达时,Flask 自动将应用上下文和请求上下文推入各自的栈中

  2. 在视图函数中可以直接访问 current_apprequestgsession

  3. 请求处理完毕后,上下文从栈中弹出,这些对象将不可访问

    应用上下文栈: 请求上下文栈:
    ┌──────────┐ ┌──────────┐
    │ current_app │ │ request │
    │ g │ │ session │
    └──────────┘ └──────────┘

7.7 手动推送上下文

在非请求环境中(如命令行脚本)使用 Flask 对象时,需要手动推送上下文:

python 复制代码
with app.app_context():
    # 在此上下文中可以使用 current_app
    current_app.logger.info('手动推送的上下文')
    print(current_app.config['DEBUG'])

八、处理响应

8.1 响应报文

HTTP 响应报文由以下部分组成:

复制代码
HTTP/1.1 200 OK                          ← 状态行
Content-Type: text/html; charset=utf-8   ← 响应头
Content-Length: 1234
Set-Cookie: session=abc123
X-Custom-Header: FlaskApp
                                          ← 空行(分隔头和体)
<!DOCTYPE html>                           ← 响应体
<html>
...
</html>
常见 HTTP 状态码
状态码 含义 说明
200 OK 请求成功
201 Created 资源创建成功
204 No Content 成功但无返回内容
301 Moved Permanently 永久重定向
302 Found 临时重定向
304 Not Modified 资源未修改,使用缓存
400 Bad Request 请求参数错误
401 Unauthorized 未认证
403 Forbidden 无权限
404 Not Found 资源不存在
405 Method Not Allowed 请求方法不允许
500 Internal Server Error 服务器内部错误

8.2 生成响应的方式

方式一:直接返回字符串

python 复制代码
@app.route('/')
def index():
    return 'Hello, World!'  # Flask 自动包装为 200 响应

方式二:返回元组

python 复制代码
@app.route('/')
def index():
    # (响应体, 状态码)
    return 'Not Found', 404

    # (响应体, 状态码, 响应头)
    return 'Hello', 200, {'X-Custom': 'value'}

    # (响应体, 响应头字典)
    return 'Hello', {'X-Custom': 'value'}

方式三:使用 make_response() 构造完整响应对象

python 复制代码
from flask import make_response

@app.route('/')
def index():
    response = make_response('Hello, World!')
    response.status_code = 200
    response.headers['X-Custom-Header'] = 'FlaskApp'
    response.headers['Content-Type'] = 'text/plain; charset=utf-8'
    response.set_cookie('username', 'zhangsan')
    return response

方式四:返回 JSON 响应

python 复制代码
from flask import jsonify

@app.route('/api/user')
def get_user():
    return jsonify({
        'name': '张三',
        'age': 25,
        'email': 'zhangsan@example.com'
    })
    # 自动设置 Content-Type: application/json

# 也可以直接返回字典(Flask 2.0+)
@app.route('/api/data')
def get_data():
    return {'key': 'value', 'count': 42}

方式五:返回模板渲染结果

python 复制代码
from flask import render_template

@app.route('/')
def index():
    return render_template('index.html', title='首页', user='张三')

方式六:返回文件响应

python 复制代码
from flask import send_file, send_from_directory

@app.route('/download')
def download():
    return send_file('files/report.pdf', as_attachment=True)

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory('uploads', filename)

8.3 Response 对象的常用属性和方法

属性/方法 说明
response.status_code 状态码
response.headers 响应头(字典类型)
response.data 响应体(bytes 类型)
response.content_type 内容类型
response.set_cookie(key, value) 设置 Cookie
response.delete_cookie(key) 删除 Cookie
response.get_data(as_text=True) 获取响应体文本

九、URL 反向解析

9.1 URL 反向解析的概念

URL 反向解析是指通过 endpoint 名称(而非硬编码 URL 字符串)来生成 URL 地址。使用 url_for() 函数实现。

9.2 url_for() 的基本用法

python 复制代码
from flask import url_for

@app.route('/')
def index():
    return '首页'

@app.route('/user/<int:user_id>')
def user_profile(user_id):
    return f'用户 {user_id}'
python 复制代码
# 在视图函数中使用
with app.test_request_context():
    print(url_for('index'))              # 输出:/
    print(url_for('user_profile', user_id=1))  # 输出:/user/1
    print(url_for('user_profile', user_id=3, page=2))  # 输出:/user/3?page=2

9.3 url_for() 的参数处理

  • URL 规则中的参数会被拼接到路径中
  • 多余的参数会被添加为查询字符串
python 复制代码
url_for('user_profile', user_id=5, tab='posts')
# 输出:/user/5?tab=posts

9.4 url_for() 在模板中使用

html 复制代码
<a href="{{ url_for('user_profile', user_id=current_user.id) }}">
    个人主页
</a>

<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>

<form action="{{ url_for('login') }}" method="post">
    ...
</form>

9.5 url_for() 的优势

对比 硬编码 URL url_for()
修改 URL 规则 需要全局替换 自动更新
可维护性
生成外部URL 不支持 url_for('index', _external=True)http://localhost:5000/
静态文件 手动拼接 url_for('static', filename='...')

9.6 生成外部 URL

python 复制代码
url_for('index', _external=True)
# 输出:http://127.0.0.1:5000/

9.7 指定 URL scheme

python 复制代码
url_for('index', _external=True, _scheme='https')
# 输出:https://127.0.0.1:5000/

十、页面重定向

10.1 重定向的概念

重定向(Redirect)是服务器告知客户端(浏览器)去访问另一个 URL 的机制。服务器返回 3xx 状态码和 Location 响应头,浏览器自动跳转。

10.2 redirect() 函数

python 复制代码
from flask import redirect, url_for

@app.route('/old-page')
def old_page():
    return redirect(url_for('new_page'))  # 重定向到新页面

@app.route('/new-page')
def new_page():
    return '这是新页面'

10.3 常见重定向场景

场景一:登录后重定向

python 复制代码
from flask import redirect, url_for, request, session

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        # 验证登录...
        session['user'] = request.form.get('username')
        next_url = request.args.get('next')  # 获取登录前的URL
        return redirect(next_url or url_for('index'))
    return '登录页面'

@app.route('/admin')
def admin():
    if 'user' not in session:
        return redirect(url_for('login', next=request.url))
    return '管理后台'

场景二:表单提交后重定向(PRG 模式)

python 复制代码
@app.route('/add', methods=['GET', 'POST'])
def add():
    if request.method == 'POST':
        # 处理表单数据...
        # Post/Redirect/Get 模式,防止重复提交
        return redirect(url_for('success'))
    return '表单页面'

@app.route('/success')
def success():
    return '操作成功'

场景三:自定义重定向状态码

python 复制代码
@app.route('/permanent-move')
def moved():
    return redirect(url_for('new_location'), code=301)  # 永久重定向

@app.route('/temp-move')
def temp_moved():
    return redirect(url_for('new_location'), code=302)  # 临时重定向(默认)

10.4 abort() 函数

用于主动抛出 HTTP 错误:

python 复制代码
from flask import abort

@app.route('/admin')
def admin():
    if not is_admin():
        abort(403)  # 抛出403错误(Forbidden)
    return '管理后台'

@app.route('/item/<int:item_id>')
def get_item(item_id):
    item = find_item(item_id)
    if not item:
        abort(404)  # 抛出404错误
    return f'物品:{item.name}'

10.5 自定义错误页面

python 复制代码
@app.errorhandler(404)
def page_not_found(error):
    return render_template('404.html'), 404

@app.errorhandler(403)
def forbidden(error):
    return render_template('403.html'), 403

@app.errorhandler(500)
def internal_error(error):
    return render_template('500.html'), 500

十一、本章小结

核心知识点回顾

知识点 核心内容
注册路由 @app.route()app.add_url_rule();endpoint 端点概念
URL 传参 路径参数 <type:var> 和查询字符串 request.args 两种方式
转换器 内置:stringintfloatpathuuidany;可自定义
处理请求 request 对象的属性和方法:argsformjsonfilesheaderscookies
请求方式 通过 methods 参数指定 GET、POST、PUT、DELETE 等
请求钩子 before_requestafter_requestteardown_request 的执行时机和用途
上下文 应用上下文(current_appg)和请求上下文(requestsession
处理响应 字符串、元组、make_response()jsonify()、模板渲染等多种方式
URL 反向解析 url_for() 根据 endpoint 生成 URL,避免硬编码
页面重定向 redirect() 重定向和 abort() 终止请求

关键导入汇总

python 复制代码
from flask import (
    Flask,           # 应用实例
    request,         # 请求对象
    session,         # 会话对象
    g,               # 请求级临时存储
    current_app,     # 当前应用实例
    url_for,         # URL反向解析
    redirect,        # 重定向
    abort,           # 中止请求
    make_response,   # 构造响应对象
    jsonify,         # JSON响应
    render_template  # 模板渲染
)
相关推荐
AI棒棒牛8 小时前
YOLO26改进创新 | 全网首发!VECA弹性核心注意力重塑全局建模,线性复杂度增强检测骨干,嘎嘎创新!
python·yolo·目标检测·yolo26·主干改进
DFT计算杂谈8 小时前
VASP新手入门: IVDW 色散修正参数
linux·运维·服务器·python·算法
清平乐的技术专栏8 小时前
【Flink学习】(六)Flink 三大时间语义 + 水位线 Watermark
大数据·学习·flink
庚昀◟8 小时前
ClaudeCode安装教程,基础使用、进阶推荐
人工智能·python·ai
楼兰公子8 小时前
《深入理解Linux网络技术内幕》配套学习大纲 + 源码Demo + 进阶实战实例
linux·arm开发·学习
楼田莉子8 小时前
C++17新特性:结构化绑定/inline变量/if相关的变化
c++·后端·学习
deephub9 小时前
告别脆弱的单体应用,用多智能体网络构建稳定的生产力工具
人工智能·python·大语言模型·多智能体
烟雨江南aabb9 小时前
Python第六弹:python爬虫篇:什么是爬虫
开发语言·爬虫·python
MomentYY9 小时前
第 1 篇:Agent 到底是什么?别被概念唬住了
人工智能·python·agent