bigywater.tech
Flask · 106

RESTful URL 设计

RESTful 的 URL 与方法在 Flask 里是怎么落地的?尾部斜杠到底会怎样?静态路径和动态路径冲突谁赢?嵌套资源要注意什么?这篇用 test_client 把每个细节逐个验证。

308
访问 /users(规则是 /users/)时的重定向状态码,保持 POST 方法
404
规则没有斜杠而请求带斜杠时的状态码
2 条
POST 同一请求发两次多出的用户数

方法与状态码

实测 · 本机执行输出
  POST /users/ → 201 /users/2 {"id":2,"name":"bob"}
  PUT /users/2 {name} → 200 {"id":2,"name":"bobby"}
  PATCH /users/2 {email} → 200 {"email":"b@x.test","id":2,"name":"bobby"}
  再 PUT 一次(整体替换,email 没了)→ 200 {"id":2,"name":"bobby"}
  DELETE /users/2 → 204 ''
  再 DELETE 一次 → 204 (这个实现是幂等的:删不存在的也返回 204)
  GET /users/2 → 404

上一篇:API 版本控制;下一篇:Idempotency-Key。

405 与 OPTIONS

实测 · 本机执行输出
  DELETE /users/ → 405 | Allow: OPTIONS, GET, HEAD, POST
  OPTIONS /users/1 → 200 | Allow: GET, HEAD, PUT, PATCH, OPTIONS, DELETE
  HEAD /users/1 → 200 | 正文长度 0 | Content-Length 22

尾部斜杠

实测 · 本机执行输出
  GET   /users    → 308 Location: http://localhost/users/
  POST  /users    → 308 Location: http://localhost/users/
  GET   /users/   → 200
  GET   /ping     → 200
  GET   /ping/    → 404

路由优先级

实测 · 本机执行输出
  GET /users/me  → {"me":true}
  GET /users/ann → {"by_name":"ann"}
  GET /users/1   → {"id":1,"name":"ann"}

转换器

实测 · 本机执行输出
  GET /items/12345678-1234-5678-1234-567812345678      → 200 {"i":"12345678-1234-5678-1234-567812345678","t":"UUID"}
  GET /items/not-a-uuid                                → 404 
  GET /files/a/b/c.txt                                 → 200 {"p":"a/b/c.txt"}
  GET /users/1/posts/2                                 → 200 {"pid":2,"uid":1}
  GET /users/x/posts/2                                 → 404 

嵌套资源

实测 · 本机执行输出
  GET /v/users/1/posts/5 → 200
  GET /v/users/2/posts/5 → 404

幂等性

实测 · 本机执行输出
  POST 两次:用户数 1 → 3(多了 2 条)
  PUT /users/50 两次:第一次后 4,第二次后 4(没有再增加)

分步演示

RESTful URL 设计
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动
    • 没有验证:strict_slashes=False 的行为、真实 HTTP 客户端对 308 的处理差异、HATEOAS 与超媒体链接、批量操作与子资源动作(如 /orders/1/cancel)的命名约定、Flask-RESTful 与 MethodView 的写法
    京ICP备2026067502号-1京公网安备11010502063487号