HTTP的Keep-Alive

普通HTTP连接在完成本次通信后就会断开。
但是我们经常会在HTTP的header里看到一段字样:

Connection: Keep-Alive

Keep-Alive连接的通信header示例

在header中的这部分代表了当前连接是一种特殊模式:keep-alive连接。这种连接在本次通信完成后并不会断开。直到某次通信时这段字样并不存在于Header中时,数据发送完成后就要断开连接。

普通HTTP连接 v.s. Keep-Alive连接(persistent connection)

Keep-Alive是HTTP/1.0中扩展支持的一种持久连接方式,在HTTP/1.1中完善并默认开启。如果想在HTTP/1.1中关闭,则需要发送
Connection: close

如何断开这种连接

要断开Keep-alive连接,client就无法使用返回EOF(-1)来判断,那么只有判断收到的数据是否是完整的。换句话说,也就是判断消息的长度。

  • Header中的Conent-Length
  • Header中的Transfer-Encoding

Conent-Length很好理解,可是如果有Transfer-Encoding解析方式就稍微复杂一些。解析规则如下:

  • 任何不含有消息体的消息(如1XX、204、304等响应消息和任何HEAD请求的响应消息),总是由一个空行(CLRF)结束。这些响应消息中可能有Conent-Length字段,但是他们的消息体长度为0。
  • Transfer-Encoding的值为非“identity”,那么transfer-length由“chunked”传输编码定义,除非消息由于关闭连接而终止。
  • Content-Length的值应当包含消息体长度。如果同时收到了非“identity”Transfer-Encoding头字段和Content-Length头字段,那么必须忽略Content-Length字段。
  • 如果消息使用媒体类型“multipart/byteranges”,并且没有通过Content-Length字段额外指定长度,那么multipart消息的各部分会指定自己的长度。multipart类型也是唯一的自定界(self-delimit)其消息体长度的类型 。除非发送者知道接收者能够解析该类型,否则不能使用该类型。
  • 如果上述规则均不符合,那么由server关闭连接来确定消息长度。(注意:client不能通过关闭连接来表示client消息的结束,因为server无法再发响应消息给client。)

为了兼容HTTP/1.0的应用,HTTP/1.1的请求消息体中必须包含一个合法的Content-Length头字段,除非知道server兼容 HTTP/1.1。
如果一个请求的消息体中不包含Content-Length字段,那么server有2种回复方式:

  • 如果不能判断消息的长度,server应该用400 (bad request) 来响应
  • 如果server仍然希望收到一个合法的Content-Length字段,用 411 (length required)来响应。

Keep-Alive可能带来的悲剧

Keep-Alive在运行效果上这么好,可是在规定中仍然强调了“应当忽略从HTTP/1.0设备接收到的Connection头字段”。
这是因为互联网并非由client和server组成,还有许许多多隐藏在链路中的proxy。那些悄无声息的proxy可能被一个Keep-Alive整的缓不过来。

Keep-Alive连接无法与不支持Connection头字段的proxy交互
(a) client发起一个消息,包含了Connection: Keep-Alive。
(b) proxy收到了这条消息,却不理解其中的Connection字段,于是默认转发给server。server收到后认为连接是Keep-Alive的,于是决定发送完当前数据部分后不会关闭连接
(c) server将响应消息发送回client,其中包括了Connection字段
(d) proxy收到响应消息后依旧默认转发。(由于proxy不理解Connection字段,所以在转发完成后希望server关闭连接(传统的HTTP连接方式)。但是server认为连接通路上的所有连接都是支持Keep-Alive方式的,所以不会关闭。这样proxy到server的连接会一直处于等待关闭的状态
(e) client收到响应消息后通过解析,发现了Connection字段,认为整个连接通路都是支持Keep-Alive通信方式的。于是通过这一条连接再次发送请求。(proxy却不一定会处理再次发送的请求,反而可能希望关闭连接。client就一直处于等待响应消息的状态)
结果就是client,proxy和server都在等待,直到某一个timeout,才关闭连接

只有当连接中的client,server和中间的所有proxy都支持HTTP/1.1,这种Keep-Alive持久连接方式才是一定有效的。若是其中任何一个是HTTP/1.0的设备,那么连接就可能有上述的问题

阅读更多
文章标签: http Keep-Alive
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭