3. HTTP 请求方法:语义与使用场景

HTTP 请求方法,说白了就是客户端告诉服务器「我想干什么」。一共定义了九种方法,但日常开发中常用的也就那么四五个。我刚开始接触 HTTP 时,总觉得 GET 和 POST 够用了,直到有一次在项目中设计 RESTful API,才发现用错方法会带来多大的麻烦。

咱们一个一个来看。

3.1 GET:获取资源

GET 是最常用的方法。它的语义很简单——请求服务器返回某个资源。浏览器地址栏输入 URL 回车,就是一次 GET 请求。

核心特征:

  • 幂等:多次请求结果相同
  • 安全:不会修改服务器状态
  • 可缓存:浏览器和代理服务器都会缓存 GET 响应
  • 请求体为空:参数通过 URL 查询字符串传递

我个人习惯把 GET 用于「只读」操作。比如获取用户列表、查询订单详情、加载文章内容。嗯,这里要注意——绝对不要用 GET 传递敏感信息。URL 会被记录在服务器日志、浏览器历史、代理缓存里,密码明文出现在 URL 上?那等于公开了。

我曾经踩过的坑:有个同事把删除操作做成了 GET 请求。结果搜索引擎爬虫路过,把整张表删了个干净。从那以后,我团队里谁再用 GET 做写操作,代码 review 直接打回。

3.2 POST:创建资源 / 提交数据

POST 的语义是「提交数据给服务器处理」。它不幂等,也不安全,更不可缓存。你想想看,提交两次表单和提交一次,结果能一样吗?

POST 的请求体可以很大,没有长度限制(理论上)。表单提交、文件上传、JSON 数据推送,都用 POST。

对比项 GET POST
幂等性 是 否
安全性 是 否
可缓存 是 否
请求体 无 有
参数位置 URL 查询字符串 请求体
数据长度 有限制(浏览器/服务器限制) 无限制
典型场景 查询、浏览 创建、提交

3.3 PUT:更新 / 替换资源

PUT 的语义是「把资源完全替换成请求体里的内容」。它是幂等的——你 PUT 同一个数据十次,结果和一次一样。

我在项目中遇到过一个问题:很多人分不清 PUT 和 POST。其实很简单——PUT 是「全量替换」,POST 是「追加创建」。比如更新用户信息,你用 PUT 就得把整个用户对象传过去,少一个字段,那个字段就被清空了。

// PUT 请求:全量替换
PUT /users/123
Content-Type: application/json

{
  "name": "张三",
  "email": "zhangsan@example.com",
  "age": 28
}

// 如果只传 name,age 会被清空
PUT /users/123
Content-Type: application/json

{
  "name": "李四"
}
// 结果:name 变成 "李四",email 和 age 变成 null

小技巧:如果你只想更新部分字段,别用 PUT,用 PATCH。PUT 是「换整辆车」,PATCH 是「换个轮胎」。

3.4 DELETE:删除资源

DELETE 的语义很直白——告诉服务器「把这个资源删掉」。它是幂等的,但注意:幂等不代表每次响应码都一样。第一次删除返回 200,第二次资源不存在返回 404,但服务器状态没变——资源确实没了。

我曾经见过一个设计:DELETE 请求返回 200 和删除的数据体。这其实不太对。按照 HTTP 规范,DELETE 成功应该返回 204 No Content,表示「操作完成,没有内容返回」。

3.5 HEAD:获取响应头

HEAD 和 GET 几乎一样,唯一的区别是——服务器不返回响应体。你想想看,什么时候需要这个?

  • 检查资源是否存在(状态码 200 vs 404)
  • 获取资源元信息(Content-Type、Content-Length)
  • 测试链接有效性
  • 检查资源是否被修改(Last-Modified、ETag)

我在做爬虫时经常用 HEAD 先探路。如果返回 404,就不浪费带宽去下载整个页面了。

3.6 OPTIONS:获取服务器支持的方法

OPTIONS 的语义是「问服务器你支持哪些方法」。服务器会在 Allow 响应头里列出允许的方法列表。

// 请求
OPTIONS /api/users HTTP/1.1
Host: example.com

// 响应
HTTP/1.1 204 No Content
Allow: GET, POST, PUT, DELETE, OPTIONS

这个方法和 CORS(跨域资源共享)关系密切。浏览器在发起跨域请求前,会先发一个 OPTIONS 预检请求,确认服务器是否允许跨域。如果服务器不配合,浏览器就直接拦截了。

3.7 PATCH:部分更新资源

PATCH 是 PUT 的补充。它只更新资源的部分字段,而不是全量替换。前面说了,PUT 是「换整辆车」,PATCH 是「换个轮胎」。

// PATCH 请求:只更新 email
PATCH /users/123
Content-Type: application/json

{
  "email": "newemail@example.com"
}
// 结果:只有 email 变了,name 和 age 保持不变

PATCH 不是幂等的。为什么?因为部分更新的语义取决于服务器实现。比如「给用户积分加 10 分」,执行两次和一次结果当然不一样。

3.8 TRACE:回显请求

TRACE 用于诊断。服务器收到 TRACE 请求后,会把请求原封不动地返回给客户端。这样客户端就能看到请求经过中间代理后有没有被篡改。

说实话,这个我几乎没用过。因为 TRACE 存在安全风险(容易引发跨站追踪攻击),大多数生产环境都禁用了它。

3.9 CONNECT:建立隧道

CONNECT 用于建立网络隧道,最常见的就是 HTTPS 代理。客户端通过 CONNECT 告诉代理服务器「帮我连接到目标服务器」,代理建立 TCP 连接后,后续数据直接透传。

你想想看,浏览器访问 HTTPS 网站时,代理服务器怎么知道该转发给谁?就是靠 CONNECT 方法告诉它的。

3.10 方法对比总览

方法 语义 幂等 安全 可缓存 请求体
GET 获取资源 ✓ ✓ ✓ 无
POST 创建/提交 ✗ ✗ ✗ 有
PUT 全量替换 ✓ ✗ ✗ 有
DELETE 删除资源 ✓ ✗ ✗ 可有可无
HEAD 获取响应头 ✓ ✓ ✓ 无
OPTIONS 查询支持方法 ✓ ✓ ✗ 无
PATCH 部分更新 ✗ ✗ ✗ 有
TRACE 回显诊断 ✓ ✓ ✗ 无
CONNECT 建立隧道 ✗ ✗ ✗ 无

3.11 知识体系图

下面这张图帮你理清九种方法的关系和分类:

HTTP 请求方法分类与语义 HTTP 请求方法 安全 & 幂等(只读) 幂等(写操作) 非幂等(写操作) GET HEAD OPTIONS TRACE PUT DELETE POST PATCH CONNECT 说明: • 安全方法:不会修改服务器资源状态 • 幂等方法:多次执行结果与一次相同(服务器状态不变) • 实际开发中,GET/POST/PUT/DELETE 覆盖了 90% 以上的场景

3.12 实际开发中的选择建议

说了这么多理论,落到实际项目里该怎么选?我总结几条经验:

  1. 查询用 GET——别问,问就是 GET。参数多?用查询字符串。参数敏感?那是设计问题,不是方法问题。
  2. 新增用 POST——除非你能保证客户端知道资源的最终 URI,那可以用 PUT。
  3. 全量更新用 PUT——客户端必须传完整资源对象。
  4. 部分更新用 PATCH——只传要改的字段。
  5. 删除用 DELETE——别整幺蛾子,别用 GET 删东西。
  6. 预检用 OPTIONS——CORS 场景下浏览器会自动发,你基本不用手动处理。

我的习惯:设计 RESTful API 时,我会在接口文档里明确标注每个端点的 HTTP 方法、是否幂等、请求体格式。这样前后端联调时少了很多扯皮。你想想看,如果后端说「这个接口用 POST」,前端问「那幂等吗」,答不上来就尴尬了。