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

持久连接降低时延和连接建立的开销,将连接保持在已调谐状态,而且减少了打开连接的潜在数量。

持久连接与并行连接配合使用可能是最高效的方式。持久连接有两种类型:比较老的 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 首部进行特殊的处理。

  • 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 首部的。

如下几个首部不能作为 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 客户端建立持久连接,除非它们了解客户端的处理能力。

HTTP之持久连接的更多相关文章

  1. asp.net signalR 专题—— 第二篇 对PersistentConnection持久连接的快速讲解

    上一篇我们快速的搭建了一个小案例,但是并没有对其中的方法进行介绍,这一篇我来逐一解析下. 一:从override的那些方法说起 不管怎么样,我们先上代码,如下: public class MyConn ...

  2. LVS持久连接

    LVS持久连接 源地址HASH ipvs的连接模板 可以通过ipvsadm -L -c 持久连接持久客户端连接 PCC:在固定时间内将来自于同一个客户端发往VIP的所有请求统统定向至同一个RS0表示所 ...

  3. php开发客服系统(持久连接+轮询+反向ajax 转载 http://www.tuicool.com/articles/2mU7v2R)

    php开发客服系统( 下载源码 ) 用户端(可直接给客户发送消息) 客服端(点击用户名.即可给该用户回复消息) 讲两种实现方式: 一:iframe + 服务器推技术comet(反向ajax,即服务器向 ...

  4. WebSocket 是什么原理?为什么可以实现持久连接?

    https://www.zhihu.com/question/20215561   作者:Ovear链接:https://www.zhihu.com/question/20215561/answer/ ...

  5. HTTP - 持久连接

    Web 客户端经常会打开到同一个站点的连接.比如,一个 Web 页面上的大部分内嵌图片通常都是来自同一个 Web 站点,而且相当一部分指向其他对象的超链接通常都指向同一个站点.因此,初始化了对某服务器 ...

  6. ASP.NET SignalR2持久连接层解析

    越是到年底越是感觉浑身无力,看着啥也不想动,只期盼着年终奖的到来以此来给自己打一针强心剂.估摸着大多数人都跟我一样犯着这样浑身无力的病,感觉今年算是没挣到啥钱,但是话也不能这么说,搞得好像去年挣到钱了 ...

  7. php开发客服系统(持久连接+轮询+反向ajax)

    欢迎在php严程序 - php教程学习AJAX教程, 本节课讲解:php开发客服系统(持久连接+轮询+反向ajax) php开发客服系统(下载源码) 用户端(可直接给客户发送消息)客服端(点击用户名. ...

  8. HTTP实现长连接(TTP1.1和HTTP1.0相比较而言,最大的区别就是增加了持久连接支持Connection: keep-alive)

    HTTP实现长连接 HTTP是无状态的 也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接.如果客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web ...

  9. HTTP协议----URI,URL,持久连接,管道与Cookie

    URI与URL有什么不同呢? URI:Universal Resource Identifier统一资源标志符 URL:Universal Resource Locator统一资源定位器 URI是用来 ...

  10. Http持久连接与HttpClient连接池

    一.背景 HTTP协议是无状态的协议,即每一次请求都是互相独立的.因此它的最初实现是,每一个http请求都会打开一个tcp socket连接,当交互完毕后会关闭这个连接. HTTP协议是全双工的协议, ...

随机推荐

  1. oracle学习笔记:update一整列 关联更新

    普通的 update 都是根据条件来对部分列的内容进行修改,用法如下: update temp_cwh_table set name = 'xxx' where id = 1; 假设现在有2张表:A. ...

  2. echart 不同颜色(柱状图)

    var option = { tooltip: { trigger: 'axis' }, grid: { left: '3%', right: '4%', bottom: '3%', containL ...

  3. 【接口自动化】mock

    mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法. 1.在测试接口时使用mock #from unittest import mock d ...

  4. 8.vue-resource 数据请求基本实现

    1.vue-resource 实现 get, post, jsonp请求:https://github.com/pagekit/vue-resource 注意: 除了 vue-resource 实现数 ...

  5. 6.Hbase 原理

    2 HBase体系结构 2.1 设计思路 HBase是一个分布式的数据库,使用Zookeeper管理集群,使用HDFS作为底层存储.在架构层面上由HMaster(Zookeeper选举产生的Leade ...

  6. 系统---添加一个相机的IP实现opencv读取rstp视频流

    系统---添加一个相机的IP实现opencv读取视频流 这里: 第一步,添加一个6段的相机IP地址:先ping 一个IP地址,ping通的是再用的IP,不可添加:ping不通的,添加IP到网络. 第二 ...

  7. Python一些细节

    1.python set() dict() 有序问题,不同版本之间的差异,与Java/C++的对比 https://www.cnblogs.com/niuxichuan/p/11608386.html ...

  8. tensorflow实战笔记(20)----textRNN

    https://www.cnblogs.com/jiangxinyang/p/10208227.html https://www.cnblogs.com/jiangxinyang/p/10241243 ...

  9. mysql 5.5 编码设置为utf8 转载自:http://outofcontrol.ca/thoughts/comments/change-mysql-5.5-default-character-set-to-utf8

    Change MySQL 5.5 default character-set to UTF8 连接里是linux下的 在window下my.ini Add under [client]  the fo ...

  10. 2020 WPF开发革命性时代,DevExpress为你护航

    下载DevExpress v19.2完整版 通过DevExpress WPF Controls,您能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的需求和构建未来新一代支持触摸 ...