bigywater.tech
Flask · 17

URL Rule 与路由匹配顺序

同一个 URL 同时能匹配好几条规则时,Flask 选哪一条?和写代码的先后顺序有关吗?这篇每种情形都用两种注册顺序各跑一遍。

50 / 100 / 200
int / string / path 转换器的权重(越小越优先)
2 种
每个实验用的注册顺序(正序与倒序),结果都相同
StateMachineMatcher
本机 Werkzeug 3.1.9 的路由匹配器类型

静态优先于动态

实测 · 本机执行输出
  /users/<name> 与 /users/me
    注册顺序 A               /users/me → fixed | /users/ann → dyn{'name': 'ann'}
    注册顺序 B(倒过来)          /users/me → fixed | /users/ann → dyn{'name': 'ann'}
    两种顺序结果相同: True

上一篇:@app.route() 如何注册路由;下一篇:path、int、float、uuid 转换器。

转换器的优先级

实测 · 本机执行输出
  /<x>(string)与 /<int:x>
    注册顺序 A               /123 → int{'x': 123} | /abc → str{'x': 'abc'} | /-5 → str{'x': '-5'}
    注册顺序 B(倒过来)          /123 → int{'x': 123} | /abc → str{'x': 'abc'} | /-5 → str{'x': '-5'}
    两种顺序结果相同: True
  /files/<name> 与 /files/<path:p>
    注册顺序 A               /files/a → name{'name': 'a'} | /files/a/b → path{'p': 'a/b'}
    注册顺序 B(倒过来)          /files/a → name{'name': 'a'} | /files/a/b → path{'p': 'a/b'}
    两种顺序结果相同: True

多个动态段

实测 · 本机执行输出
  /<a>/<b>、/<a>/x、/api/<b>
    注册顺序 A               /1/x → ax{'a': '1'} | /1/y → ab{'a': '1', 'b': 'y'} | /api/x → api_b{'b': 'x'} | /api/zz → api_b{'b': 'zz'}
    注册顺序 B(倒过来)          /1/x → ax{'a': '1'} | /1/y → ab{'a': '1', 'b': 'y'} | /api/x → api_b{'b': 'x'} | /api/zz → api_b{'b': 'zz'}
    两种顺序结果相同: True

重复的规则

实测 · 本机执行输出
    先注册 first、后注册 second → GET /dup: first
    先注册 second、后注册 first → GET /dup: second

同路径不同方法

实测 · 本机执行输出
    GET    /x → 200 'GET 端点'
    POST   /x → 200 'POST 端点'
    PUT    /x → 405 '<!doctype html>\n<htm'
    DELETE /x → 405 '<!doctype html>\n<htm'

权重

实测 · 本机执行输出
    iter_rules 顺序(按注册顺序,不排序): ['/users/<name>', '/users/me', '/<x>', '/<int:x>']
    每条规则被拆成片段,每个片段有权重(取自私有属性 Rule._parts;权重越小优先级越高):
      /users/<name>    [静态 users [(0, -5)]]  [动态 [100]]
      /users/me        [静态 users [(0, -5)]]  [静态 me [(0, -2)]]
      /<x>             [动态 [100]]
      /<int:x>         [动态 [50]]

匹配器与斜杠合并

实测 · 本机执行输出
    url_map 的匹配器: StateMachineMatcher | merge_slashes = True
    GET /users//me → 308 | Location = http://localhost/users/me

分步演示

匹配顺序
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。权重取自私有属性 Rule._parts,版本不同可能变化
    • 没有验证:Werkzeug 2.2 之前的旧匹配器(按排序后的规则列表匹配)的行为、host_matching 与 subdomain 对顺序的影响、defaults 与 redirect_to 规则的匹配、大量规则(几千条)时的匹配耗时
    京ICP备2026067502号-1京公网安备11010502063487号