HTTP之持久链接

HTTP/1.1 容许 HTTP 设备在事务处理结束以后将 TCP 链接保持在打开状态,以便为将来的 HTTP 请求重用现存的链接。在事务处理结束后仍然保持在打开状态的 TCP 链接被称为持久链接。非持久链接会在每一个事务结束以后关闭。持久链接会在不一样事务之间保持打开状态,直到客户端或服务器决定将其关闭为止。web

持久链接下降时延和链接创建的开销,将链接保持在已调谐状态,并且减小了打开链接的潜在数量。浏览器

持久链接与并行链接配合使用多是最高效的方式。持久链接有两种类型:比较老的 HTTP/1.0+ "keep-alive" 链接,以及现代的 HTTP/1.1 "persistent" 链接。缓存

Keep-Alive 操做

实现 HTTP/1.0 keep-alive 链接的客户端能够经过包含 Connection: Keep-Alive 首部请求将一条链接保持在打开状态。服务器

若是服务器愿意为下一条请求将链接保持在打开状态,就在响应中包含相同的首部。若是响应中没有 Connection: Keep-Alive 首部,客户端就认为服务器不支持 keep-alive,会在发回响应报文以后关闭链接。
编码

Keep-Alive 选项

Keep-Alive 首部只是请求将链接保持在活跃状态。发出 keep-alive 请求以后,客户端和服务器并不必定会赞成进行 keep-alive 会话。它们能够在任意时刻关闭空闲的 keep-alive 链接,并可随意限制 keep-alive 链接所处理事务的数量。设计

能够用 Keep-Alive 通用首部中指定的、由逗号分隔的选项来调节 keep-alive 的行为:代理

  • 参数 timeout 是在 Keep-Alive 响应首部发送的。它估计了服务器但愿将链接保持在活跃状态的时间。这并非一个承若值。
  • 参数 max 是在 Keep-Alive 响应首部发送的。它估计了服务器还但愿为多少个事务保持此链接的活跃状态。这并非一个承若值。
  • Keep-Alive 首部还可支持未经处理的属性,这些属性主要用于诊断和调试。语法为 name [=value]。

Keep-Alive 首部彻底是可选的,但只有在提供 Connection: Keep-Alive 时才能使用它。下面示例的 Keep-Alive 说明服务器最多还会为另外 5 个事务保持链接的打开状态,或者将打开状态保持到链接空闲了 2 分钟以后。调试

Connection: Keep-Alive
Keep-Alive: max=5, timeout=120

Keep-Alive 链接的限制和规则

  • 在 HTTP/1.0 中,keep-alive 并非默认使用的。客户端必须发送一个 Connection: Keep-Alive 请求首部来激活 keep-alive 链接。
  • Connection: Keep-Alive 首部必须随全部但愿保持持久链接的报文一块儿发送。若是客户端没有发送 Connection: Keep-Alive 首部,服务器就会在那条请求以后关闭链接。
  • 客户端探明响应中没有 Connection: Keep-Alive 响应首部,就能够知道服务器发出响应以后是否会关闭链接了。
  • 只有在无需检测到链接的关闭便可肯定报文实体主体部分长度的状况下,才能将链接保持在打开状态--也就是说实体的主体部分还必须有正确的 Content-Length,有多部件媒体类型,或者用分块传输编码的方式进行了编码。在 keep-alive 信道中回送错误的 Content-Length 是很糟糕的事,这样事务处理的另外一端就没法精确地检测到一条报文的结束和另外一条报文的开始了。
  • 代理和网关必须执行 Connection 首部的规则。代理或网关必须在将报文转发出去或将其高速缓存以前,删除在 Connection 首部中命名的全部首部字段以及 Connection 首部自身。
  • 不该该与没法肯定是否支持 Connection 首部的代理服务器创建 keep-alive 链接,以防止出现下面的哑代理问题。但在实际应用中不是总能作到这一点。
  • 从技术上讲,应该忽略全部来自 HTTP/1.0 设备的 Connection 首部字段(包括 Connection: Keep-Alive),由于它们多是由比较老的代理服务器误转发的。
  • 除非重复发送请求会产生其余一些反作用,不然若是在客户端收到完整响应以前链接就关闭了,客户端就必定要作好重试请求的准备。

Keep-Alive 和哑代理

1. Connection 首部和盲中继

问题出在代理上--尤为是那些不理解 Connection 首部,并且不知道在沿着转发链路将其发送出去以前,应该将该首部删除的代理。不少老的或简单的代理都是盲中继(blind relay),它们只是将字节从一个链接转发到另外一个链接中去,不对 Connection 首部进行特殊的处理。
code

  • Web 向代理发送包含 Connection: Keep-Alive 首部的报文,期待创建一个 keep-alive 链接;
  • 哑代理收到这条请求,但并不理解 Connection 首部(只是将其做为一个扩展首部对待)。所以只是沿着转发链路将报文一字不漏地发送给服务器。但 Connection 首部是个逐跳首部,只适用于单条传输链路,不该该沿着传输链路向下传输。
  • 通过中继的 HTTP 请求到达 Web 服务器。当 Web 服务器收到通过代理转发的 Connection: Keep-Alive 首部时,会误觉得代理但愿进行 keep-alive 对话,所以回送一个 Connection: Keep-Alive 响应首部。因此,此时 Web 服务器认为它在与代理进行 keep-alive 对话,会遵循 keep-alive 规则。但代理却对 keep-alive 一无所知。
  • 哑代理将 web 服务器的响应报文回送给客户端,并未来自 web 服务器的 Connection: Keep-Alive 首部一块儿传送过去。客户端看到这个首部,会认为代理赞成进行 keep-alive 对话。因此,此时客户端和服务器都认为它们在进行 keep-alive 对话,但与它们进行对话的代理却对 keep-alive 一无所知。
  • 因为代理不知道 keep-alive,因此会将收到的全部数据都回送给客户端,而后等待源端服务器关闭链接。但源端服务器会认为代理已经显式地请求它将链接保持在打开状态了,因此不会去关闭链接。这样,代理就会挂在那里等待链接的关闭。
  • 客户端收到回送的响应报文时,会当即转向下一条请求,在 keep-alive 链接上向代理发送另外一条请求。而代理并不认为同一条请求上会有其余请求到来,请求被忽略,浏览器就挂在那里了。
  • 这种错误的通讯方式会使浏览器一直处于挂起状态,直到客户端或服务器未来链接超时,并将其关闭为止。

代理和逐跳首部

为避免这类代理通讯问题的发生,现代的代理都毫不能转发 Connection 首部和全部名字出如今 Connection 值中的首部。所以,若是一个代理收到了一个 Connection: Keep-Alive 首部,是不该该转发 Connection 首部,或全部名为 Keep-Alive 首部的。blog

以下几个首部不能做为 Connection 首部值列出,也不能被代理转发或做为缓存相应使用的首部:Proxy-Authenticate、Proxy-Connection、Transfer-Encoding 和 Upgrade。

插入 Proxy-Connection

对盲中继的变通作法是引入了一个名为 Proxy-Connection 的新首部,解决了在客户端后面紧跟着一个盲中继所带来的问题--但并无解决全部其余状况下存在的问题。

浏览器会向代理发送非标准的 Proxy-Connection 扩展首部,而不是官方支持的著名的 Connection 首部。若是代理是盲中继,它会将无心义的 Proxy-Connection 首部转发给 Web 服务器,服务器会忽略此首部,不会带来任何问题。但若是是可以理解持久链接的代理,就用一个 Connection 首部取代无心义的 Proxy-Connection 首部,而后将其发送给服务器。

Proxy-Connection 首部修正了单个盲中继带来的问题:

对有多层次代理的状况,Proxy-Connection 仍然没法解决问题:

HTTP/1.1 持久链接

HTTP/1.1 逐渐中止了对 keep-alive 链接的支持,用一种名为持久链接(persistent connection)的改进型设计取代了它。

HTTP/1.1 持久链接在默认状况下是激活的。除非特别指明,不然 HTTP/1.1 假定全部链接都是持久的。要在事务处理结束以后将链接关闭,HTTP/1.1 应用程序必须向报文中显式地添加一个 Connection: close 首部。可是,客户端和服务器仍然能够随时关闭空闲的链接。不发送 Connection: close 并不意味着服务器承若永远将链接保持在打开状态。

持久链接的限制和规则

  • 发送了 Connection: close 请求首部以后,客户端就没法在那条链接上发送更多的请求了。
  • 若是客户端不想在链接上发送其余请求了,就应该在最后一条请求中发送一个 Connection: close 请求首部。
  • 只有当链接上全部的保卫都有正确的、自定义报文长度时--也就是说,实体主体部分的长度都和相应的 Connection-Length 一致,或者是用分块传输编码方式编码的--链接才能持久链接。
  • HTTP/1.1 的代理必须可以分别管理与客户端和服务器的持久链接--每一个持久链接都只适用于一跳传输。
  • HTTP/1.1 的代理服务器不该该与 HTTP/1.O 客户端创建持久链接,除非它们了解客户端的处理能力。
相关文章
相关标签/搜索