一条泥憨鱼头像
关注
【从0开始学习计算机网络】| HTTP方法疑点解析封面图

【从0开始学习计算机网络】| HTTP方法疑点解析

🌈个人主页:一条泥憨鱼(欢迎各位大佬莅临)

                                                               🎬精选专栏传送门:

                                            ❄️《数据结构》   ❄️《AI与Agent那些事》

                                            ❄️《从0开始学计算机网络》 ❄️

前言:

一团队接过一个线上事故:某核心接口的 QPS 突然暴跌,监控面板上一片飘红。查了半天,发现是前端同学把所有请求都改成了 POST——理由是"POST 能传的参数更多,还不会把数据暴露在 URL 里"。

结果呢?缓存层全部失效,因为 CDN 和浏览器根本不缓存 POST 请求。数据库被读请求打到冒烟,接口响应时间从 20ms 飙到 3s。

这个事故让我意识到:很多写了几年代码的人,其实并没有真正理解 HTTP 方法。今天就把这事掰开揉碎了讲清楚。

先搞清楚 HTTP 方法到底在干嘛

很多人把 HTTP 方法理解成"数据放在哪"——GET 放 URL,POST 放 body。这完全跑偏了。

HTTP 方法本质上是一个语义声明:它告诉服务器和中间件(缓存、代理、网关),你想对某个资源做什么操作。

拿快递打个比方。快递单上有个"操作类型"栏,写着"签收"还是"退回"。这个字段决定了快递员怎么处理这个包裹,而不是决定包裹里装了什么。

同理,HTTP 方法告诉服务器:

- GET:我想这个资源

- POST:我想创建一个资源

- PUT:我想整体替换这个资源

- DELETE:我想删掉这个资源

这个语义一旦被忽略,整个 HTTP 生态的协作机制就乱了——缓存不知道能否复用响应,网关不知道能否安全重试,服务器不知道请求是否幂等。

六个常用方法逐个拆解

日常开发最常见的就这六个。我把它们分成两组:查和改

查:GET 和 HEAD

GET 是最常用的。它的语义是"获取资源"。特点:

- 幂等:发 100 次和发 1 次,结果一样,资源状态不变

- 可缓存:响应可以被浏览器、CDN 缓存

- 参数在 URL 上(query string)

# 获取用户列表,page=1 表示第一页

resp = requests.get("https://api.example.com/users?page=1")

HEAD 和 GET 几乎一样,唯一的区别是服务器不返回响应体,只返回响应头。适合用来"探路":

# 检查文件是否存在、大小多少,不用下载整个文件

resp = requests.head("https://cdn.example.com/bigfile.zip")

print(resp.headers["Content-Length"])  # 文件大小

改:POST、PUT、DELETE

POST 的语义是"在服务器上创建一个新资源"。它不幂等——发两次就创建两个。

# 创建新用户,每次调用都会生成一个新用户

resp = requests.post("https://api.example.com/users", json={

    "name": "张三",

    "email": "[email protected]"

})

PUT 的语义是"用请求体**整体替换**指定资源"。它幂等——发多少次,最终资源状态都一样。

# 整体更新用户 ID=123 的信息,如果不存在就创建

resp = requests.put("https://api.example.com/users/123", json={

    "name": "李四",

    "email": "[email protected]"

})

DELETE 的语义是"删除指定资源"。它幂等——删一次和删十次,最终结果都是"没了"。

# 删除用户 ID=123

resp = requests.delete("https://api.example.com/users/123")

探路:OPTIONS

OPTIONS 用来查询服务器支持哪些方法。这在 CORS 跨域请求里用得最多——浏览器在发正式请求之前,会先发一个 OPTIONS 预检请求。

# 查看 /users 端点支持哪些 HTTP 方法

resp = requests.options("https://api.example.com/users")

print(resp.headers.get("Allow"))

# 输出类似:GET, POST, PUT, DELETE, OPTIONS

GET 和 POST 的本质区别

这是今天的重头戏。网上很多文章讲"GET 参数在 URL,POST 参数在 body",这没错,但只是表象。

本质区别有三个维度。

维度一:语义——查 vs 改

GET 语义是"查询",POST 语义是"创建(或触发某个操作)"。

这个区别决定了服务器怎么处理请求。GET 请求不应该改变服务器上的任何数据——不该创建文件、不该写数据库、不该改状态。

你见过有人把"删除用户"做成 GET 请求吗?有,而且不少。这类接口被爬虫爬到、被预加载扫到,数据就没了。

维度二:幂等性

这是最容易被忽略、但影响最深远的区别。

- GET 幂等:重试任意多次都安全

- POST 不幂等:重试会导致重复创建

幂等性在网络重试场景下至关重要。客户端发请求超时了,它不知道服务器到底处理了没有。如果请求是 GET,它可以放心重试;如果是 POST,重试可能导致重复下单、重复扣款

所以支付接口通常要求客户端生成一个唯一的 `request_id`,服务端靠它来去重。这就是在给 POST 补幂等性。

维度三:缓存机制

- GET 可以被浏览器、CDN、反向代理缓存

- POST 默认不缓存(HTTP 规范也明确要求)

这就是开头那个事故的根源。前端把所有请求改成 POST,等于主动关掉了整个链路的缓存能力。每次请求都穿透到源站,数据库当然扛不住。

实际开发中的踩坑建议

说了这么多理论,落到实操上,有几个原则值得记住。

按语义选方法,别按"参数放哪"选

很多团队图省事,把所有写操作都做成 POST。短期的确方便,但长期来看,接口的语义模糊了,调用方只能靠文档猜测这个接口是否幂等、能否重试。

别用 GET 干改的活

有人为了省事,用 GET 传 `?action=delete&id=123`。这是定时炸弹。浏览器预加载、爬虫、搜索引擎都可能触发这个请求。

POST 和 PUT 别混用

- 创建用 POST:客户端不知道资源 ID

- 整体更新用 PUT:客户端知道资源 ID

如果你把更新接口设计成 POST `/users/123/update`,语义上就矛盾了——POST 是创建,但你明明在更新。

幂等性要显式设计

不是所有 POST 都能天然幂等,但你可以通过 `request_id` 去重来"补课":

def create_order(request_id: str, order_data: dict):

    # 先查 request_id 是否处理过

    if redis.exists(f"req:{request_id}"):

        return {"status": "duplicate"}

   

    # 处理业务逻辑

    order = create_order_in_db(order_data)

   

    # 标记 request_id 已处理

    redis.set(f"req:{request_id}", order.id, ex=3600)

    return {"status": "ok", "order_id": order.id}

怎么选?一张表搞定

回到开头那个事故。如果当时团队能按下面的决策表来选,缓存就不会全挂。

操作类型方法幂等可缓存
查询资源GET
只拿响应头HEAD
创建新资源POST
整体替换资源PUT
删除资源DELETE
查询支持的方法OPINTIONS

简单的决策逻辑:

1. 想东西 → GET

2. 想创建新东西 → POST

3. 想整体替换已有东西 → PUT(知道资源 ID)

4. 想东西 → DELETE

5. 只需要响应头 → HEAD

6. 跨域调试 → OPTIONS

结语

HTTP 方法不是约定俗成的"习惯",而是整个 Web 生态协作的基础契约。尊重这套语义,你的接口才能正确享受缓存、重试、安全防护等基础设施的能力。不尊重它,迟早要付出代价——可能是缓存全挂,也可能是数据被爬虫误删。

如果你之前没有认真想过这些方法之间的区别,希望这篇文章能帮你少踩几个坑。下次设计接口时,先问自己一句:这个操作,语义上到底是"查"还是"改"?答案会帮你做出正确的选择。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/2503_94545876/article/details/163396830

文章来源crawl

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--