1020 字
约 3 分钟
7
S10-B05 · Flask 路由与错误页

适用读者:要写一个小服务、或要接手 Flask 老项目的人。
前置:S10-B03。
实测环境:Flask 3.1.3 / Python 3.12.3(2026-11-05 真实启动 + curl)。
覆盖旧文:A-1495(Flask 路由注册,38 点)、A-1496(404/500 错误页,32 点)= 70 点。
覆盖扩展:E-S10-007(errorhandler 与 abort)。
上一篇:S10-B04 · FastAPI 入门:类型即文档
下一篇:S10-J01 · 依赖治理。


1. 一句话结论

Flask 是"微框架":给你路由和请求上下文,其余(校验、文档、异步)都要自己接。灵活,但一致性靠团队纪律。

能力 Flask FastAPI(对照)
路由 @app.route @app.get/post
参数校验 手写 / 第三方(pydantic 可接) 内建(422 明细)
文档 需扩展(flask-smorest 等) 内建 /docs
异步 3.x 支持,但生态多为同步 原生 async def
学习曲线 最低 低(但要懂类型标注)

2. 实测:路由注册

from flask import Flask, jsonify, abort

app = Flask(__name__)

@app.route("/items/<int:item_id>")
def item(item_id):
    if item_id > 100:
        abort(404)                 # 抛 404,交给 errorhandler
    return jsonify(id=item_id, name="apple")

路由的三件事:

要素 说明
@app.route(path) 注册路径;<int:item_id> 是转换器(类型转换 + 匹配约束)
视图函数返回值 字符串(HTML)/ jsonify(JSON)/ (body, status) 元组
方法限制 默认只允许 GET;methods=["POST"] 显式声明

转换器类型:<int:>、<float:>、<path:>(含 /)、<uuid:>、默认 <string>(不含 /)。

2.1 实测响应

$ curl -s http://127.0.0.1:19061/items/5
{"id":5,"name":"apple"}

3. 自定义错误页(E-S10-007)

@app.errorhandler(404)
def nf(e):
    return jsonify(error="not found"), 404

@app.errorhandler(500)
def se(e):
    return jsonify(error="internal"), 500

@app.route("/boom")
def boom():
    raise RuntimeError("人为异常")

实测:

$ curl -s -w " [HTTP %{http_code}]" http://127.0.0.1:19061/items/200
{"error":"not found"} [HTTP 404]

$ curl -s -w " [HTTP %{http_code}]" http://127.0.0.1:19061/boom
{"error":"internal"} [HTTP 500]

要点:

点 说明
errorhandler 是按状态码注册 可对 404/500/403 分别定义
必须返回 (body, status) 只返回 body 会变成 200
abort(404) 会触发 handler 单纯 return "x", 404 不会触发(差异容易踩)
未捕获异常 → 500 生产环境应关闭 debug=True,否则返回调试页而非你的 JSON

安全提醒:app.run(debug=True) 在生产会泄露源码与堆栈;部署应用 WSGI(gunicorn/uwsgi)+ 关闭 debug。


4. 与 FastAPI 的一处关键差异(实测对照)

同一个"路径参数类型不匹配"的请求:

请求 Flask FastAPI
/items/abc 404(转换器不匹配,路由根本没命中) 422(路由命中,参数校验失败)

为什么重要:

语义 含义
Flask 的 404 "这个 URL 不存在" —— 客户端会以为接口没了
FastAPI 的 422 "参数类型不对" —— 客户端知道是自己传错了

这条差异直接决定前端能不能做"参数错误提示"。迁移时(J02)要显式处理。


5. 五个易踩点

坑 说明
debug=True 上生产 源码泄露 + 交互式调试器可执行代码
只 return body 不返回 status 状态码变 200
abort 与 return tuple 混用 后者不触发 errorhandler
路由尾斜杠 /items 与 /items/ 默认视为不同(strict_slashes)
蓝图(Blueprint)忘记注册 路由 404,且不易发现(注册在 app.register_blueprint)

6. 自检

  1. <int:item_id> 与 <item_id> 的区别是什么?
  2. abort(404) 与 return ..., 404 都会触发 errorhandler 吗?
  3. 为什么 Flask 对 /items/abc 返回 404 而 FastAPI 返回 422?
  4. 生产环境为什么必须关闭 debug?
  5. 蓝图未注册会有什么现象?

7. 下一篇

S10-J01 · 依赖治理:requirements / environment.yml / 锁版本

两个框架都跑通了,下一步是"让它们在别人机器上也跑通"。下一篇给出可复现的三件套:Python 版本锁定、精确版本、哈希校验。


本篇属于系列《S10 · Python 语言与环境》。旧文来源:A-1495/A-1496;扩展点 E-S10-007。Flask 3.1.3 响应为 2026-11-05 实测。

S10-B05 · Flask 路由与错误页
https://www.clxhxhhr.top/posts/5320/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。