bigywater.tech
Flask · 20

路由中的尾部斜杠行为

/projects 与 /projects/ 到底是不是同一个 URL?访问另一种形式会怎样?POST 会不会丢?这篇用两个规则和 308 重定向把规则讲清楚。

308
不带斜杠访问 /projects/ 规则时的状态码
404
带斜杠访问 /about 规则时的状态码
2.8×
经过一次 308 重定向后的耗时倍数(test client)

带不带斜杠

实测 · 本机执行输出
  请求                   状态     Location / 正文
  GET /projects/       200    projects 列表
  GET /projects        308    http://localhost/projects/
  GET /about           200    about 页面
  GET /about/          404    <html lang=en>
  GET /loose           200    loose
  GET /loose/          200    loose
  GET /loose2          200    loose2
  GET /loose2/         200    loose2

上一篇:自定义 URL Converter;下一篇:url_for() 如何反向生成 URL。

308 与 POST

实测 · 本机执行输出
  POST /submit(规则是 /submit/)→ 308 | Location = http://localhost/submit/
  follow_redirects=True → 200 submitted | 重定向历史: [(308, 'POST')]

Location 头

实测 · 本机执行输出
  GET http://example.test:8080/projects → Location = http://example.test:8080/projects/ | autocorrect_location_header = False

url_for

实测 · 本机执行输出
  url_for 的结果: {'projects': '/projects/', 'about': '/about', 'loose': '/loose'}

strict_slashes

实测 · 本机执行输出
  strict_slashes = False: {'/projects': 200, '/projects/': 200, '/about': 200, '/about/': 200}
  同时注册 /x 与 /x/: {'/x': (200, 'no-slash'), '/x/': (200, 'with-slash')}

重定向的代价

实测 · 本机执行输出
  直接访问 /projects/:75.5 µs;访问 /projects(重定向后再请求):209.0 µs(约 2.8 倍,因为多发了一个请求)

分步演示

尾部斜杠
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:反向代理(Nginx)在 Host 头不同时 Location 的内容(见第 175 篇 ProxyFix)、浏览器对 308 缓存的行为、旧版本 Werkzeug 中 301 的表现、merge_slashes 与尾部斜杠同时发生时的重定向次数
    京ICP备2026067502号-1京公网安备11010502063487号