如何解释“Connection: keep-alive, close”?

41

据我所了解,HTTP连接可以是keep-aliveclose

我向服务器发送了一个HTTP请求:

GET /page1/ HTTP/1.1
Host: server.com
Connection: keep-alive

然后它回应说:

HTTP/1.1 200 OK
Connection: keep-alive, close

我认为服务器存在缺陷,因为像keep-alive, close的响应是模糊的。

然而,作为接收方,我们应该如何处理这样的消息?我们应该将此标题值解释为keep-alive还是close


1
你读过HTTP协议的RFC吗?http://tools.ietf.org/html/rfc2616 - Jack
1
这可能与尝试支持[certain] HTTP 1.0客户端有关,请参见http://en.wikipedia.org/wiki/HTTP_persistent_connection。然而,由于`close`(在1.1中定义)被指定,因此符合HTTP 1.1服务器/客户端的解释是“不是持久连接”? - user166390
@Jack,似乎没有包含答案...... - Pacerier
4个回答

31

TL; DR:Chrome将此响应头解释为keep-alive,并保持持久连接,而Firefox则关闭每个连接。

我在优化我的网站页面加载时间时遇到了这个问题。

在引用的RFC中,我没有找到关于如何正确处理Connection头中多个条目的任何信息。对我来说,它似乎可以从两种可能性中选择:

  1. 如果有多个条目,则可以选择最适合您需求的
  2. 如果包含close,则可以在传输后关闭连接

所以,我需要找出答案。让我们进行一些深入的调查:

我注意到Chrome始终使用Connection:keep-alive发送HTTP / 1.1请求,而我的Apache默认配置始终响应带有Connection:close头的请求。因此,我开始研究并使用Wireshark查看TCP段。

Chrome需要获取14个元素才能显示该网站,其中大部分是静态内容,如图像或CSS文件。它需要14个TCP连接,并且需要很长时间(大约1.2秒)。在每次请求图像(例如)后,会出现一个设置了FIN标志为1的TCP段。

那么Chrome与Firefox如何对比呢?Chrome似乎对一个服务器的并发连接数有6个的最大限制。Firefox具有更精细的配置,并区分持久性(最多6个,在about:config中看到)和非持久性(不同来源的最大数字差异很大)。但是等等... Chrome和Firefox都发送带有Connection:keep-alive的HTTP / 1.1请求头,因此两者都应限制为6个(因为这是请求打开持久连接的方法)。

我决定尝试一个简单的技巧,并将以下行添加到我的web根目录中的.htaccess文件中:

<ifModule mod_headers.c>
Header set Connection keep-alive
</ifModule>
服务器现在的响应是:

Connection: keep-alive, close

现在我重新查看了TCP段:Chrome到我的服务器只有9个连接,其中只有3个设置了FIN标志位。所以这个技巧似乎起作用了。但是为什么会有那3个连接,在数据传输后关闭了连接?这些是PHP请求,因为HTTP头X-Powered-By: PHP/5.4.11予以确认。

那Firefox呢?还有14个请求!

如何修复并使fcgi进程也支持keep-alive?

我在httpd.conf配置文件的虚拟主机部分添加了以下行:

KeepAlive On
KeepAliveTimeout 5
MaxKeepAliveRequests 100

已经移除了在.htaccess中添加的部分。现在服务器不再发送任何令人困惑的 - Connection: keep-alive, close,而是只有Connection: keep-alive,一切正常运作!

结论:

一个带有连接字段设置为

HTTP/1.1 200 OK
Connection: keep-alive, close

Chrome会将其解释为keep-alive,而Firefox似乎会关闭每个连接。这似乎取决于实际的实现。

因此,如果您想要处理包含Connection: keep-alive, close响应标头的客户端实现,我建议尝试使用keep-alive,如果您需要多个请求。最坏的情况是:服务器将关闭连接,您需要重新连接(这正是您本来可以选择的另一个选项!)


那么应该是适当的行为呢? - Pacerier
由于RFC没有提到如何处理这种情况,我会假设(如果你像客户端一样):根据你的需求选择最佳方案!如果没有需要传输的内容,则关闭连接;如果队列中仍有请求,则保持连接活动状态。这是我个人认为Chrome处理方式的做法。 - ConcurrentHashMap
当RFC在许多方面保持沉默却被认为是权威指南时,这难道不会让人感到恼火吗? - Pacerier
非常有趣,我进行了谷歌速度测试,它抱怨这个保持连接关闭的事情,并显示保持连接未启用。因此,我将其更改为“keep-alive”(不带close),速度测试的“警告”消失了。 - Codebeat

4
您正在使用 HTTP/1.1,但指定了 Connection: keep-alive
HTTP/1.1 中,Connection: keep-alive 标头已被弃用,因此不应发送它。所有连接默认都是长连接。 Connection: keep-alive 是在所谓的 HTTP/1.0+ 时代使用的小技巧。(+ 代表“必须使用的技巧”)。
在 O'Reilly 出版的《HTTP权威指南》(作者:Brian Totty、Marjorie Sayer、Sailu Reddy、Anshu Aggarwal、David Gourley)中,我们可以看到:
“保持活动状态已被弃用,并且在当前的 HTTP/1.1 规范中不再记录。但是,浏览器和服务器仍然相对常用地使用保持活动状态握手,因此 HTTP 实现者应准备与之进行互操作。”
在 HTTP 术语中,“互操作”意味着“接受任何荒谬的内容而不是向您发出错误”。
那是因为Web开发人员宁愿被恶意攻击,也不愿收到错误信息。(你可以据此判断JavaScript的流行程度。) 请参阅健壮性原则(wikipedia)(又称Postel定律)和Trevor Jim - Postel's Law is not for you

3
这意味着服务器不会进行持久连接,并将在此请求后关闭连接。

那么为什么一开始要说保持连接呢? - Pacerier
2
可能是因为你发送了 keep-alive。你不应该发送 keep-alive,因为在 HTTP 1.1 中它已经被假定了,keep-alive 只用于 HTTP 1.0。 - Francis Upton IV

2
答案在RFC 7230 - 6.1 连接中。它说:

The Connection header field's value has the following grammar:

 Connection        = 1#connection-option
 connection-option = token
在互联网RFC术语中,1#connection-option表示至少一个或最多任意数量的connection-option。这意味着可能有多个选项,接收方会选择它喜欢的任何一个选项。这不是模糊性,而是一种选择。

1
这不是完整的语法,而是一般性的语法。虽然发送多个“连接选项”可能是有效的,但这可能仅限于某些连接选项。例如,根据第6.2/6.3节,“Connection: keep-alive, close”没有任何意义。 - Pacerier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接