强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 04 章:HTTP 方法详解

第 04 章:HTTP 方法详解

HTTP 方法定义了客户端对资源的"意图"。正确理解和使用 HTTP 方法,是构建和调试 RESTful API 的基础。


4.1 HTTP 方法概览

HTTP/1.1 规范(RFC 9110)定义了以下常用方法:

方法语义幂等安全请求体常见用途
GET获取资源查询数据
HEAD获取资源元数据检查资源是否存在、获取头信息
POST创建资源/提交数据创建新资源、提交表单
PUT替换整个资源更新完整资源
PATCH部分更新资源更新部分字段
DELETE删除资源可选删除资源
OPTIONS查询支持的方法CORS 预检请求
TRACE回显请求诊断(通常被禁用)
CONNECT建立隧道HTTPS 代理

幂等(Idempotent):多次请求结果相同。GET/PUT/DELETE 是幂等的,POST 不是。 安全(Safe):不修改服务器状态。GET/HEAD/OPTIONS/TRACE 是安全的。


4.2 GET — 获取资源

GET 是最常用的 HTTP 方法,用于从服务器获取资源。

基本 GET

# 最简单的 GET
curl https://httpbin.org/get

# 带查询参数
curl "https://httpbin.org/get?page=1&limit=20&sort=date"

# 使用 -G 和 --data-urlencode 自动编码参数
curl -G https://httpbin.org/get \
  --data-urlencode "q=hello world" \
  --data-urlencode "lang=zh"

# 设置 Accept 头,指定返回格式
curl -H "Accept: application/json" https://api.example.com/users
curl -H "Accept: text/html" https://api.example.com/users
curl -H "Accept: application/xml" https://api.example.com/users

GET 常见业务场景

# 分页查询
curl "https://api.example.com/users?page=2&per_page=50"

# 过滤查询
curl "https://api.example.com/orders?status=paid&date_from=2024-01-01"

# 搜索
curl -G https://api.example.com/search \
  --data-urlencode "q=机器学习" \
  --data-urlencode "category=技术"

# 获取特定资源
curl https://api.example.com/users/42

# 获取关联资源
curl https://api.example.com/users/42/orders

# 缓存控制:使用 If-None-Match 条件请求
curl -H "If-None-Match: \"abc123\"" https://api.example.com/data

GET 的注意事项

# ❌ 错误:GET 不应该有请求体(虽然 curl 允许,但不符合语义)
curl -X GET https://api.example.com/users -d '{"filter": "active"}'

# ✅ 正确:将参数放在 URL 中
curl -G https://api.example.com/users \
  --data-urlencode "filter=active"

# ❌ 错误:不要用 GET 执行修改操作
curl -X GET https://api.example.com/users/42/delete

# ✅ 正确:使用 DELETE 方法
curl -X DELETE https://api.example.com/users/42

4.3 HEAD — 获取元数据

HEAD 方法与 GET 类似,但服务器只返回响应头,不返回响应体。

基本 HEAD

# 获取响应头(-I 等价于 -X HEAD 并隐藏响应体)
curl -I https://example.com

# 输出示例:
# HTTP/2 200
# content-type: text/html; charset=UTF-8
# content-length: 1256
# date: Sat, 10 May 2026 12:00:00 GMT
# etag: "abc123"
# last-modified: Fri, 09 May 2026 10:00:00 GMT

# 使用 -X HEAD(效果类似,但会显示下载进度)
curl -X HEAD -s -o /dev/null -w "%{http_code}" https://example.com

HEAD 的业务场景

# 检查资源是否存在
status=$(curl -s -o /dev/null -w "%{http_code}" -I https://api.example.com/users/42)
if [ "$status" = "200" ]; then
  echo "用户存在"
elif [ "$status" = "404" ]; then
  echo "用户不存在"
fi

# 检查文件大小(不下载)
curl -sI https://example.com/largefile.zip | grep -i content-length
# 输出:content-length: 104857600

# 检查文件类型
curl -sI https://example.com/download | grep -i content-type
# 输出:content-type: application/pdf

# 检查是否需要认证
curl -s -o /dev/null -w "%{http_code}" -I https://api.example.com/private
# 401 → 需要认证

# 检查 CORS 头
curl -sI -H "Origin: https://myapp.com" https://api.example.com/data \
  | grep -i "access-control"

# 获取 Last-Modified 用于条件下载
curl -sI https://example.com/file.tar.gz | grep -i last-modified

4.4 POST — 创建/提交数据

POST 是语义最丰富的方法,用于创建资源、提交表单、上传文件等。

基本 POST

# 发送表单数据(application/x-www-form-urlencoded)
curl -X POST https://httpbin.org/post \
  -d "username=admin&password=secret123"

# 发送 JSON 数据
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "secret123"}'

# 从文件发送 JSON
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/json" \
  -d @payload.json

# 发送原始文本
curl -X POST https://httpbin.org/post \
  -H "Content-Type: text/plain" \
  -d "Hello, World!"

# 发送 XML
curl -X POST https://httpbin.org/post \
  -H "Content-Type: application/xml" \
  -d '<?xml version="1.0"?><user><name>张三</name></user>'

POST 的业务场景

# 创建用户
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "name": "张三",
    "email": "[email protected]",
    "role": "developer"
  }'

# 提交订单
curl -X POST https://api.example.com/orders \
  -H "Content-Type: application/json" \
  -d '{
    "product_id": 42,
    "quantity": 2,
    "shipping_address": "北京市朝阳区"
  }'

# 文件上传(multipart/form-data)
curl -X POST https://api.example.com/upload \
  -F "file=@/path/to/document.pdf" \
  -F "description=季度报告"

# 触发 Webhook
curl -X POST https://hooks.example.com/deploy \
  -H "Content-Type: application/json" \
  -H "X-Hook-Secret: my-secret" \
  -d '{"event": "push", "ref": "main"}'

# 发送邮件(SMTP)
curl --url "smtp://smtp.example.com:587" \
  --ssl-reqd \
  --mail-from "[email protected]" \
  --mail-rcpt "[email protected]" \
  --user "[email protected]:password" \
  -T email.txt

4.5 PUT — 完整替换资源

PUT 用于替换目标资源的全部内容。PUT 是幂等的——多次执行结果相同。

基本 PUT

# 更新整个资源
curl -X PUT https://api.example.com/users/42 \
  -H "Content-Type: application/json" \
  -d '{
    "name": "张三(已更新)",
    "email": "[email protected]",
    "role": "senior-developer",
    "department": "工程部"
  }'

# 替换配置文件
curl -X PUT https://api.example.com/config/web \
  -H "Content-Type: application/json" \
  -d @config.json

# 上传文件到指定位置(S3 风格)
curl -X PUT https://storage.example.com/bucket/file.txt \
  -H "Content-Type: text/plain" \
  -d "这是文件的新内容"

PUT vs POST 的区别

# POST:创建新资源(服务器分配 ID)
# 每次执行可能创建不同的资源
curl -X POST https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"name": "张三"}'
# 响应:201 Created, Location: /users/42

# PUT:替换指定 ID 的资源
# 如果不存在则创建,存在则更新
curl -X PUT https://api.example.com/users/42 \
  -H "Content-Type: application/json" \
  -d '{"name": "张三"}'
# 响应:200 OK 或 201 Created

4.6 PATCH — 部分更新

PATCH 用于对资源进行部分修改,只发送需要变更的字段。

基本 PATCH

# 仅更新邮箱字段
curl -X PATCH https://api.example.com/users/42 \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]"}'

# 更新多个字段
curl -X PATCH https://api.example.com/users/42 \
  -H "Content-Type: application/json" \
  -d '{
    "role": "tech-lead",
    "salary": 50000
  }'

# 使用 JSON Merge Patch(RFC 7396)
curl -X PATCH https://api.example.com/settings \
  -H "Content-Type: application/json" \
  -d '{"theme": "dark"}'

# 使用 JSON Patch(RFC 6902)
curl -X PATCH https://api.example.com/users/42 \
  -H "Content-Type: application/json-patch+json" \
  -d '[
    {"op": "replace", "path": "/name", "value": "李四"},
    {"op": "add", "path": "/tags/-", "value": "vip"},
    {"op": "remove", "path": "/temp_field"}
  ]'

PUT vs PATCH 对比

特性PUTPATCH
语义完整替换部分更新
幂等性✅ 是❌ 否(通常)
请求体完整资源仅变更部分
缺失字段会被删除/置空保持不变
带宽较大较小
Content-Typeapplication/jsonapplication/json 或 application/json-patch+json

4.7 DELETE — 删除资源

基本 DELETE

# 删除单个资源
curl -X DELETE https://api.example.com/users/42
# 响应:204 No Content

# 删除带认证保护的资源
curl -X DELETE https://api.example.com/users/42 \
  -H "Authorization: Bearer $TOKEN"

# 批量删除(通过请求体)
curl -X DELETE https://api.example.com/users \
  -H "Content-Type: application/json" \
  -d '{"ids": [42, 43, 44]}'

# 软删除(通过 PATCH 设置 deleted 标记)
curl -X PATCH https://api.example.com/users/42 \
  -H "Content-Type: application/json" \
  -d '{"deleted": true, "deleted_at": "2026-05-10T12:00:00Z"}'

# 确认删除结果
curl -s -o /dev/null -w "%{http_code}" \
  -X DELETE https://api.example.com/users/999
# 204 → 成功删除
# 404 → 资源不存在

4.8 OPTIONS — 查询支持的方法

OPTIONS 用于查询服务器支持哪些 HTTP 方法,也是 CORS 预检请求的机制。

基本 OPTIONS

# 查询服务器支持的方法
curl -X OPTIONS https://api.example.com/users -v

# 查看 Allow 头
curl -s -X OPTIONS -I https://api.example.com/users | grep -i allow
# 输出:Allow: GET, POST, PUT, DELETE, OPTIONS

# CORS 预检请求
curl -X OPTIONS https://api.example.com/data \
  -H "Origin: https://myapp.com" \
  -H "Access-Control-Request-Method: POST" \
  -H "Access-Control-Request-Headers: Content-Type, Authorization"

# 查看 CORS 响应头
curl -sI -X OPTIONS https://api.example.com/data \
  -H "Origin: https://myapp.com" \
  -H "Access-Control-Request-Method: POST" \
  | grep -i "access-control"

CORS 预检请求详解

# 完整的 CORS 预检流程

# 1. 浏览器先发送 OPTIONS 请求
curl -v -X OPTIONS https://api.example.com/data \
  -H "Origin: https://myapp.com" \
  -H "Access-Control-Request-Method: DELETE" \
  -H "Access-Control-Request-Headers: Authorization, Content-Type"

# 2. 检查响应中的 CORS 头
# Access-Control-Allow-Origin: https://myapp.com
# Access-Control-Allow-Methods: GET, POST, PUT, DELETE
# Access-Control-Allow-Headers: Authorization, Content-Type
# Access-Control-Max-Age: 86400

# 3. 如果预检通过,浏览器才会发送实际请求
curl -X DELETE https://api.example.com/users/42 \
  -H "Origin: https://myapp.com" \
  -H "Authorization: Bearer token"

4.9 数据格式

常见 Content-Type 对比

Content-Type格式适用场景curl 方式
application/x-www-form-urlencodedkey=value&key2=value2HTML 表单-d "key=value"
multipart/form-data分段边界文件上传-F "key=value"
application/jsonJSONREST API-d '{"key":"value"}'
application/xmlXMLSOAP/旧系统-d '<key>value</key>'
text/plain纯文本日志/原始数据-d 'text'
application/octet-stream二进制流文件上传--data-binary @file
application/grpcgRPC 协议微服务通信见第 13 章

格式转换示例

# 发送 JSON,请求 XML 响应
curl -X POST https://api.example.com/data \
  -H "Content-Type: application/json" \
  -H "Accept: application/xml" \
  -d '{"key": "value"}'

# 发送表单,请求 JSON 响应
curl -X POST https://api.example.com/data \
  -H "Accept: application/json" \
  -d "name=张三&age=30"

# 发送 CSV
curl -X POST https://api.example.com/import \
  -H "Content-Type: text/csv" \
  --data-binary @data.csv

注意事项

  1. GET 不要有 Body:虽然技术上可行,但违反语义且可能被代理丢弃
  2. POST 不是幂等的:重复提交 POST 可能创建重复资源,使用幂等键(Idempotency-Key)可解决
  3. PUT 要发送完整资源:不要只发送部分字段,缺失字段可能被清空
  4. DELETE 可能有 Body:虽然少见,但 RFC 允许 DELETE 携带请求体
  5. 安全考虑:生产环境通常禁用 TRACE 方法(防止跨站追踪攻击)
# 幂等键示例(防止重复创建)
curl -X POST https://api.example.com/payments \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"amount": 100, "currency": "CNY"}'

扩展阅读


📖 下一章第 05 章:请求头与响应头 — 深入了解 HTTP 头部的管理,包括自定义头、Cookie 和 Content-Type。