HTTP POST请求发送两个TCP包?

本文通过实际测试揭示了HTTP POST请求的真相,指出并非所有POST请求都会分成多个TCP包发送,并探讨了不同浏览器及编程库在处理POST请求时的行为差异。

今天瞎逛的时候看到有一篇16年的文章,说99%的人理解错了HTTP中GET与POST的区别。前面大部分文章都没问题,但是最后有一个,被作者奉为大boss的区别:

我读得书少,你不要骗我。于是我随手拿公司的http服务,做了一次post请求然后用wireshark抓了个包,结果:

 

好了,http的一个post请求只发了一个tcp包,不用怀疑。

 

然后为了不愿望作者,我仔细看了原文,后面还提到,浏览器先发送header,然后发送body。。。嗯,难道意思是浏览器做了这个动作,而用postman发送就没有?于是我又进一步测试一下网站里有没有post请求。所以我在一个网页上做了一个post请求,结果:

可以看到,一个post请求,实际上,还是只有一个tcp包,整个就给他打包过去了, 先发送header什么的,至少在我的测试里面不存在的。

 

那么真的不存在一个post请求分两个tcp包过去的情况吗?我不知道,至少在我知道的范围内,没看过。

 

2018年1月5日补充:

嗯,有朋友提到,人家最后确实写了firefox抓到的包是一个。是我批判过急了。我原文也说的是不确定是不是就没有发两个包的浏览器。

另外,为表诚意,我仔细搜索了相关内容,发现确实是有发两个包的情况的,但是并不是跟作者说的那样,先发post的header,返回一个100继续,而是先发一个tcp包,把header发过去,然后因为nagle算法的原因,就等待一个tcp的ack,然后再发剩下的包。

原文章在这里,主要内容是作者发现post比get多200ms,然后深入研究,发现ruby的net::HTTP库,会将一个http请求拆分,先发送header部分。另外,由于没有设置TCP_NODELY,所以第一个包之后要等待ack,才发下一个包,导致了一个请求有200ms的延迟。有一个中文博客引用了这篇文章。不过我没用过ruby,不能直接测试,也不清楚是不是真的如此,或者这个问题已经被修复,有测试过的朋友请一定告诉我。

2018年8月8日补充:

我补充了一片文章后续,有兴趣的朋友可以看看。

关于“GET请求发送一个TCP数据POST请求发送两个”的说法,其实是一种**常见的误解或简化描述**,并不完全准确。实际情况取决于多个因素,HTTP协议版本、请求体大小、网络缓冲机制、TCP的MSS(最大段大小)、是否启用Nagle算法等。 但我们可以从原理上解释为什么会有这种说法: --- ### ✅ 为什么有人说“GET一个POST两个”? #### 1. **GET 请求结构简单** - GET 请求将参数放在URL中,请求头较短。 - 整个 HTTP 请求请求行 + 请求头)通常较小,可以**一次性封装在一个 TCP 数据**中发送。 示例: ``` GET /search?q=hello HTTP/1.1 Host: example.com Connection: close ``` 这个请求总长度可能不到200字节,适合放入一个TCP报文段(通常MSS约1460字节)。 ➡️ 所以:**一次TCP发送即可完成**。 --- #### 2. **POST 请求请求体** - POST 请求的数据在请求体中(如表单提交、JSON等),需要额外的字段 `Content-Length` 实际数据。 - 虽然理论上也可以在一个TCP发送,但在某些情况下(尤其是早期浏览器或特定实现中),可能会出现: - 第一个发送**请求头** - 第二个发送**请求体** 但这并不是因为协议规定要分两步,而是由于: - **延迟发送(Nagle算法)**:避免小浪费带宽。 - **应用层写入方式**:比如先写头部,再写正文,未及时flush。 - **TLS分片(HTTPS)**:加密后数据变大,可能分片。 - **操作系统或库的缓冲策略** > 🔍 关键点:如果POST数据很小(比如几十字节),现代浏览器服务器通常仍会将其合并为**一个TCP**发送。 --- ### 📌 实际情况总结 | 情况 | 是否可能一个? | 说明 | |------|------------------|------| | 小GET请求 | ✅ 是 | 通常一个TCP搞定 | | 小POST请求 | ✅ 可能是一个 | 现代实现常合并 | | 大POST请求 | ❌ 很可能多个 | 数据太大必须分段 | --- ### 技术验证方法(可选) 你可以使用 Wireshark观察真实行为: - 访问同一个服务,分别用 GET POST 提交相似内容。 - 观察 TCP 层的 `[PSH, ACK]` 数量。 你会发现在大多数现代环境下,即使是 POST,只要数据不大,也常常是**一个TCP**发送完毕。 --- ### 结论 > “GET发一个POST两个” 是一种**经验性、简化的说法**,用来强调: > - GET 请求轻量、无主体; > - POST 请求有实体,可能导致更多网络交互; > > 但它**不是TCPHTTP协议的强制规则**。 --- ```python # 示例:使用requests发送POST请求(底层仍走TCP) import requests # 即使这样简单的POST,在底层也可能只占一个TCP response = requests.post("https://httpbin.org/post", data={"key": "value"}) print(response.json()) ```
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值