本系列:00 导读 · 01补 网络基础 · 01 心智模型 · 02 路由与数据模型 · 02补 HTTP 方法对比(本文) · 02补2 状态码共识 · 03 依赖注入与分层 · 04 中间件异常日志 · 05 异步后台与流式 · 06 鉴权与安全 · 07 测试与项目骨架 · 08 实战 HTTP↔MCP
行文:T3 辨析篇(工具书体) | 本篇方法:对比 + 费曼 | 辅助:组块化、主动回忆
定位:01补 讲「HTTP 是请求–响应」;02 讲 Path/Query/Body 怎么写。本文专讲 Method(方法):为什么不止 GET/POST、各自语义从哪来、场景与坑。成功/失败如何用数字表达见 02补2 状态码。
规范依据:以 RFC 9110(HTTP 语义)为主;REST 风格是约定而非协议强制。社区写 API 时优先遵守「安全 / 幂等」语义,再谈资源路径怎么切。
0. 一张总表(先建立坐标)

| 方法 | 一句话意图 | 安全 | 幂等 | 常可缓存 | 典型成功码 | FastAPI 装饰器 |
|---|---|---|---|---|---|---|
| GET | 取资源表示 | ✓ | ✓ | ✓(常) | 200 | @app.get |
| HEAD | 只要头、不要正文 | ✓ | ✓ | ✓(同 GET) | 200 | @app.head / 自动 |
| OPTIONS | 问服务器允许什么 | ✓ | ✓ | ✗ | 200 / 204 | @app.options / CORS |
| POST | 处理提交;常=创建子资源 | ✗ | ✗ | ✗ | 201 / 200 / 202 | @app.post |
| PUT | 用请求体整体替换目标资源 | ✗ | ✓ | ✗ | 200 / 201 / 204 | @app.put |
| PATCH | 部分修改目标资源 | ✗ | 有条件† | ✗ | 200 / 204 | @app.patch |
| DELETE | 删除目标资源 | ✗ | ✓ | ✗ | 200 / 204 / 202 | @app.delete |
| TRACE | 回显请求(诊断) | ✓ | ✓ | ✗ | 200 | 一般禁用 |
| CONNECT | 隧道(代理/HTTPS) | — | — | — | — | 应用层几乎不用 |
† PATCH 是否幂等取决于你怎么定义补丁;JSON Merge Patch 常可做成幂等,JSON Patch 操作序列则不一定。
段末注释:安全(safe)指语义上不应改服务器状态;幂等(idempotent)指同一请求故意重复多次,效果与成功一次等价。后文沿用。
1. 产生背景:方法从哪来、解决什么问题
1.1 简史对照
| 阶段 | 有什么方法 | 要解决的问题 |
|---|---|---|
| HTTP/0.9 | 实质只有取文档 | 取静态页 |
| HTTP/1.0 | GET / HEAD / POST | 表单提交、上传;区分「取」与「交」 |
| HTTP/1.1 | + PUT / DELETE / OPTIONS / TRACE / CONNECT | 可写的分布式超媒体、代理、诊断 |
| 后来扩展 | PATCH(RFC 5789)等 | 「改一部分」不必整资源替换 |
浏览器时代长期只用 GET(链接触发) 与 POST(表单),导致很多人误以为「API 只有这两种」。现代 API(含 FastAPI)按 资源语义 选用方法,才能让缓存、重试、网关、OpenAPI 文档有一致预期。
1.2 两个正交属性:安全 × 幂等

| 安全 | 非安全 | |
|---|---|---|
| 幂等 | GET、HEAD、OPTIONS | PUT、DELETE(及多数「写同一最终态」的设计) |
| 非幂等 | (规范上安全方法应幂等) | POST(典型);某些 PATCH |
为什么网关/客户端在乎这两属性?
- 安全方法可被预取、爬虫、缓存更激进地使用;用 GET 做「删号」「扣款」会酿灾。
- 幂等方法在超时后可安全重试;非幂等重试可能双下单——需幂等键或改用 PUT。
1.3 费曼一句
方法不是「URL 后面的花活」,而是对服务器的动词合同:我这次是来「看」、来「交一份新活」、还是「把这个位子换成我说的样子」。合同错了,中间所有代理、缓存、重试逻辑都会按错误假设行动。
2. 方法分论:背景 · 场景 · 用法 · 局限
2.1 GET — 获取表示
| 维度 | 说明 |
|---|---|
| 背景 | 最早、最核心;链接、书签、搜索引擎都默认「点一下 = GET」 |
| 场景 | 查详情、列表、导出只读视图、健康检查 |
| 语义 | 安全、幂等;响应常可缓存(看 Cache-Control) |
| 局限 | ① URL+Query 有长度限制(代理/浏览器);② 规范上不应依赖请求体(部分客户端丢 body);③ 敏感参数进 Query 易进日志/Referer |
| 反模式 | GET /orders/1/cancel 取消订单;GET /pay?amount= 扣款 |
1 | from fastapi import FastAPI, Query |
2.2 HEAD — 只要元数据
| 维度 | 说明 |
|---|---|
| 背景 | 与 GET 同语义,但响应无 body,省带宽 |
| 场景 | 探活文件是否存在、拿 Content-Length/ETag、CDN 校验 |
| 用法 | FastAPI/Starlette 常对已注册的 GET 自动支持 HEAD;也可显式 @app.head |
| 局限 | 服务端仍可能做完整计算再丢弃 body——「省」的是传输,不一定省算力;实现必须与 GET 头信息一致 |
2.3 POST — 提交处理 / 创建
| 维度 | 说明 |
|---|---|
| 背景 | 表单与「非幂等动作」容器;REST 里常映射「在集合下创建成员」 |
| 场景 | 创建资源、/search 复杂查询(body 很大)、触发非幂等动作(下单、发送邮件)、批量导入 |
| 语义 | 非安全、非幂等;重复提交可能产生多个资源 |
| 成功码 | 创建资源多用 201 + Location;异步受理用 202;动作结果直接返回可用 200 |
| 局限 | 超时重试易双写 → 需要 Idempotency-Key 或业务去重;缓存不友好 |
1 | from fastapi import FastAPI, status |
2.4 PUT — 整体替换(或按 URI 创建)
| 维度 | 说明 |
|---|---|
| 背景 | 客户端声明「这个 URI 的完整内容应当是……」;幂等写入 |
| 场景 | 上传完整配置文档、按客户端指定 ID 创建/覆盖、全量更新 |
| 语义 | 非安全、幂等:同一 PUT 连打 N 次 ≈ 一次成功后的状态 |
| 与 POST 对比 | POST 常「服务器分配 ID」;PUT 常「客户端选定 URI」 |
| 局限 | ① 大资源全量传,带宽差;② 并发易丢更新(需 ETag/If-Match);③ 「漏传字段」被当成「清空」——易踩坑 |
1 |
|
2.5 PATCH — 部分更新
| 维度 | 说明 |
|---|---|
| 背景 | RFC 5789:避免为改一个字段而 PUT 整文档 |
| 场景 | 改邮箱、改状态机一步、JSON 补丁文档 |
| 语义 | 非安全;幂等性取决于补丁格式与实现 |
| 局限 | ① 无单一标准 body(JSON Merge Patch / JSON Patch / 自定义);② OpenAPI/客户端对「部分字段」约定要文档写清;③ 与 PUT 混用导致团队语义分裂 |
1 | from pydantic import BaseModel |

2.6 DELETE — 删除
| 维度 | 说明 |
|---|---|
| 背景 | 与 PUT 对称的写操作;幂等:删一次与删多次,资源都应「不在了」 |
| 场景 | 删资源、取消订阅(若建模为删关系) |
| 成功码 | 204 无正文常见;200 可带被删摘要;异步删 202 |
| 局限 | ① 「软删除」仍改状态,语义要在文档声明;② 带 body 的 DELETE 兼容性差,过滤条件优先放 Query;③ 已删除再删应仍 200/204(幂等),不要改成 404 除非产品坚持「暴露不存在」 |
1 | from fastapi import Response, status |
2.7 OPTIONS — 能力发现 / CORS 预检
| 维度 | 说明 |
|---|---|
| 背景 | 询问目标资源允许哪些方法;浏览器 CORS 预检会发 OPTIONS |
| 场景 | 跨域前端调 API;调试「这个路径允不允许 PUT」 |
| 用法 | 生产多由 CORSMiddleware 自动应答;业务很少手写 @app.options |
| 局限 | 预检失败时表现为「前端神秘挂了」——根因常在方法/头不在 Allow/Access-Control-Allow-* |
段末注释:CORS(跨源资源共享,Cross-Origin Resource Sharing)是浏览器限制跨站读响应的机制;预检(preflight)用 OPTIONS 问清服务器是否允许本次跨域请求。
2.8 TRACE / CONNECT — 知道即可
| 方法 | 用途 | API 服务建议 |
|---|---|---|
| TRACE | 沿路径回显,排障 | 关闭(信息泄露、XST 风险) |
| CONNECT | 代理建立隧道 | 由代理/网关处理,业务 FastAPI 不暴露 |
3. 核心对比专题
3.1 POST vs PUT vs PATCH(写操作三角)
| 问题 | POST | PUT | PATCH |
|---|---|---|---|
| 目标 URI 通常指向? | 集合或「动作处理器」 | 具体资源 | 具体资源 |
| 创建时谁决定 ID? | 常服务器 | 常客户端(URI 已定) | 一般不负责「首次创建」 |
| 更新粒度 | 不限(语义最宽) | 全量替换 | 部分修改 |
| 重复提交 | 可能多个资源 | 同一最终态 | 视补丁而定 |
| 选谁的经验法则 | 「提交一份处理」或「集合下新建」 | 「这个地址的内容就是这份」 | 「只改若干字段」 |
易混例:
| 需求 | 更合适 | 别写成 |
|---|---|---|
| 新建订单,ID 服务器生成 | POST /orders |
PUT /orders(无明确 ID) |
客户端上传 config/v1 整文件 |
PUT /configs/v1 |
反复 POST /configs |
| 只改用户手机号 | PATCH /users/1 |
PUT 却漏传其它字段导致清空 |
| 「支付」非幂等动作 | POST /payments + 幂等键 |
GET /pay |
3.2 GET vs POST(只读查询的灰色地带)
| 条件 | 倾向 GET | 倾向 POST |
|---|---|---|
| 参数短、可放 Query | ✓ | |
| 参数极长/结构深 | ✓(如复杂搜索 DSL) | |
| 要被缓存、可分享链接 | ✓ | |
| 查询本身有副作用(写审计且不可接受重复) | 谨慎 | 用 POST,或 GET+异步审计解耦 |
行业常见妥协:POST /search 表示「只读但 body 很大」——偏离严格 REST,但务实;须在文档标明无副作用,避免网关按 POST 禁缓存时误伤性能预期。
3.3 安全方法里塞写操作(历史包袱)
部分旧站点用 GET /delete?id= 只因「<a href> 只能 GET」。在 API 中这是明确错误:爬虫、预取、日志回放都可能触发删除。
4. FastAPI / ASGI 层落地注意
4.1 装饰器与 OpenAPI
1 | from fastapi import APIRouter, FastAPI |
- 同一路径可注册不同方法;OpenAPI 会分开展示。
- 未实现的方法由框架返回 405 Method Not Allowed(并常带
Allow头)。
4.2 Body 与方法的搭配习惯
| 方法 | Body | 说明 |
|---|---|---|
| GET / HEAD | 不建议 | 部分中间件/客户端忽略 |
| POST / PUT / PATCH | 常见 | JSON / 表单 / 文件 |
| DELETE | 尽量不用 | 兼容性差 |
| OPTIONS | 通常无业务 body | 预检由中间件处理 |
路径与 Query/Body 组块细节见 02。
4.3 幂等与重试(和异步篇的交界)
客户端超时后重试 PUT/DELETE 通常安全;重试 POST 前需要:
- 业务幂等键(头如
Idempotency-Key),或 - 把「创建」改成可 PUT 的「客户端指定 URI」,或
- 先查后建的条件 API
异步任务受理见 05 的 202 + BackgroundTasks / 队列边界。
5. 局限性总览(按层)
| 层 | 局限 | 启示 |
|---|---|---|
| 协议语义 | 方法不传输「业务动词」细节 | 复杂动作用 POST /resources/{id}/actions/... 或领域路径,并写清副作用 |
| 浏览器 | 表单只好发 GET/POST | 前端 API 调用用 fetch/axios 才能发 PUT/PATCH/DELETE |
| 缓存/CDN | 默认主要信任 GET/HEAD | 误用 GET 写数据会被缓存成事故 |
| 代理/网关 | 可能剥离冷门方法或 body | 上线前用真实链路测 DELETE/PATCH |
| 团队约定 | PUT/PATCH 混用 | 项目 README 钉死一种更新策略 |
| 安全 | TRACE、错误的 CORS OPTIONS | TRACE 关;CORS 白名单收敛 |
6. 踩坑对照表(T3)
| # | 现象 | 根因 | 修法 |
|---|---|---|---|
| 1 | 爬虫误删数据 | 删除做成 GET | 改 DELETE + 鉴权 |
| 2 | 超时后双订单 | POST 无幂等键被重试 | 幂等键或改 PUT |
| 3 | PATCH 后字段变 null |
模型默认值覆盖「未传字段」 | exclude_unset=True |
| 4 | PUT 「更新」清掉其它列 | 把部分字段当全量 | 改 PATCH,或 PUT 要求完整文档 |
| 5 | 浏览器控制台 CORS 报错 | OPTIONS 预检失败 | 配 CORSMiddleware 允许方法/头 |
| 6 | GET 带超长 JSON body 偶发失败 | 中间件丢 body / 长度墙 | 改 POST /search |
| 7 | 删除返回 404 导致重试警报 | 非幂等风格 | 已删仍 204 |
| 8 | OpenAPI 试出来 405 | 路径有、方法未注册 | 补装饰器或改客户端方法 |
7. 选型决策树(实操)
1 | 要读数据且无副作用? |
8. 合书自测
- 用一句话区分 安全 与 幂等;举一个「非安全但幂等」的方法。
- 为什么「取消订单」不应做成 GET?会触发哪些现实风险?
- 同一资源「改邮箱」选 PUT 还是 PATCH?各有什么代价?
- POST 创建超时后客户端重试,如何避免双资源?列出两种方案。
- OPTIONS 在浏览器里最常见的用途是什么?
9. 闪卡候选
| 正面 | 背面 |
|---|---|
| GET 是否幂等/安全? | 都是 |
| POST 是否幂等? | 通常否 |
| PUT 核心语义? | 用 body 替换目标 URI 的完整表示 |
| PATCH 来自哪个需求? | 部分更新,免全量传输 |
| DELETE 再删一次规范期望? | 仍成功(幂等),资源保持不存在 |
| 405 含义? | 路径认识但方法不允许 |
| 浏览器预检用何方法? | OPTIONS |