【发布时间】:2015-05-01 07:31:30
【问题描述】:
在几个 Internet 资源中,我看到了一个一般性建议,即禁用发送 Expect: 100-continue HTTP 标头,以便在客户端实际上不发送大型正文时提高性能。
但是,测试以下代码表明,发送标头会使总时间平均减少约 50 毫秒。
var hc = new HttpClient();
hc.DefaultRequestHeaders.ExpectContinue = ?;
hc.BaseAddress = new Uri("http://XXX/api/");
var r = new HttpRequestMessage(HttpMethod.Post, new Uri("YYY", UriKind.Relative))
{
Content = new StringContent("{}", Encoding.UTF8, @"application/json")
};
var tt = hc.SendAsync(r).Result;
tt.Content.ReadAsStringAsync().Result.Dump();
hc.Dispose();
这里是请求的 WireShark 转储,Expect: 100-continue
1 0.000000000 ss.ss.ss.176 dd.dd.dd.150 TCP 66 54515→80 [SYN] Seq=0 Win=8192 Len=0 MSS=1260 WS=4 SACK_PERM=1
2 0.342137000 dd.dd.dd.150 ss.ss.ss.176 TCP 66 80→54515 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 WS=1 SACK_PERM=1
3 0.342687000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [ACK] Seq=1 Ack=1 Win=66780 Len=0
4 *REF* ss.ss.ss.176 dd.dd.dd.150 HTTP 272 POST /XXX/api/YYY HTTP/1.1
5 0.361158000 dd.dd.dd.150 ss.ss.ss.176 HTTP 79 HTTP/1.1 100 Continue
6 0.361846000 ss.ss.ss.176 dd.dd.dd.150 TCP 56 54515→80 [PSH, ACK] Seq=219 Ack=26 Win=66752 Len=2
7 0.705497000 dd.dd.dd.150 ss.ss.ss.176 HTTP 461 HTTP/1.1 200 OK (application/json)
8 0.726029000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [FIN, ACK] Seq=221 Ack=433 Win=66348 Len=0
9 1.067923000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54515 [FIN, ACK] Seq=433 Ack=222 Win=65535 Len=0
10 1.068466000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54515→80 [ACK] Seq=222 Ack=434 Win=66348 Len=0
不带header的相同请求:
11 9.300455000 ss.ss.ss.176 dd.dd.dd.150 TCP 66 54516→80 [SYN] Seq=0 Win=8192 Len=0 MSS=1260 WS=4 SACK_PERM=1
12 9.640626000 dd.dd.dd.150 ss.ss.ss.176 TCP 66 80→54516 [SYN, ACK] Seq=0 Ack=1 Win=8192 Len=0 MSS=1380 WS=1 SACK_PERM=1
13 9.641393000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [ACK] Seq=1 Ack=1 Win=66780 Len=0
14 *REF* ss.ss.ss.176 dd.dd.dd.150 HTTP 250 POST /XXX/api/YYY HTTP/1.1
15 0.406794000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54516 [ACK] Seq=1 Ack=197 Win=65535 Len=0
16 0.406963000 ss.ss.ss.176 dd.dd.dd.150 TCP 56 54516→80 [PSH, ACK] Seq=197 Ack=1 Win=66780 Len=2
17 0.749589000 dd.dd.dd.150 ss.ss.ss.176 HTTP 461 HTTP/1.1 200 OK (application/json)
18 0.769053000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [FIN, ACK] Seq=199 Ack=408 Win=66372 Len=0
19 1.109276000 dd.dd.dd.150 ss.ss.ss.176 TCP 54 80→54516 [FIN, ACK] Seq=408 Ack=200 Win=65535 Len=0
20 1.109742000 ss.ss.ss.176 dd.dd.dd.150 TCP 54 54516→80 [ACK] Seq=200 Ack=409 Win=66372 Len=0
IIS 7.5、IIS 8.0 收到相同的结果
问题是:
- 是什么让带有 Expect 标头的请求执行得更快,而理论上会发生相反的情况?
- POST 请求的主体是否总是包含在单独的 TCP 数据包中(我只查看了几个示例,这是真的)?这里我的意思是为什么转储中第 14 行的 TCP 数据包不包含第 16 行 TCP 数据包中发送的数据(POST 正文)?
【问题讨论】:
-
如果没有看到捕获中的数据,很难回答第一个问题。看起来实际的 POST 数据分别包含在数据包 4 和 14 中,因为它们的大小为 250+ 字节。数据包 15 和 16 有点可疑 - 没有理由额外往返。在一般层面上,不 - HTTP 客户端通常不会将 POST 数据与元数据分离到请求中的不同 TCP 数据包中。
-
还有一个观察:如果禁用 Nagle 算法 (ServicePointManager.UseNagleAlgorithm = false),那么提供 Expect 标头或不提供几乎没有区别。但 POST 正文仍被推送到不同的 TCP 数据包中。
-
HttpWebRequest 和 .NET Framework 也有同样令人讨厌的问题
标签: c# performance http iis http-headers