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. VBA运算符(九)

    运算符可以用一个简单的表达式定义,例如:4 + 5等于9.这里,4和5称为操作数,+被称为运算符.VBA支持以下类型的运算符 - 算术运算符 比较运算符 逻辑(或关系)运算符 连接运算符 算术操作符 ...

  2. 线程池工具ThreadPoolExecutor

    JDK1.5中引入了强大的concurrent包,其中最常用的莫过了线程池的实现ThreadPoolExecutor,它给我们带来了极大的方便,但同时,对于该线程池不恰当的设置也可能使其效率并不能达到 ...

  3. vue.js 初步学习

    跟着b站上的视频来学 首先什么是vue.js? 跟着b站上视频来学:(o゚v゚)ノ <!DOCTYPE html> <html lang="en"> < ...

  4. 用pythoninstall cefpython打包exe,制作自己的浏览器

    cefpython浏览器 介绍 用pythoninstall cefpython打包exe,制作自己的浏览器, 软件架构 PyInstaller: 3.4 Python: 3.5.4 Platform ...

  5. Computer Vision_33_SIFT:Object recognition from local scale-invariant features——1999

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  6. gdb无法单步调试

    使用gdb调试单步程序时如果打印提示“single stepping until exit from function xxx,which has no line number information ...

  7. Windows与Linux之间文件传输

    (1).使用WinSCP工具,实现将Windows的文件上传到Linux指定目录下 (1).输入主机名.用户名.密码,选择登录,成功连接至Linux系统 (2).在左侧列表,选择要上传文件,单击右键选 ...

  8. linux基础--命令使用

    rpm命令 rpm -qa 包 查看包是否安装 rpm qa 列出系统安装的所有包 rpm -ql 包 查看软件包安装的位置及配置的目录 rpm -ivh 包 安装rpm包或强制安装包 rpm -Uv ...

  9. C# 开发的windows服务 不能调试——讨论整理

    CSDN的标题:C# 开发的windows服务 不能调试 System.Diagnostics.Debugger.Launch();在想加断点的地方加入这行,是进入断点的,可以进行调试,我的是xp系统 ...

  10. BCB6 使用TZCompressionStream压缩

          最近由于项目需要涉及到解压第三方公司的数据,在此做一下记录环境部署和使用方法,免得以后忘记.    对方公司的数据是通过TCompressionStream 压缩之后,存到数据库中,采用的 ...