这是我阅读《HTTP权威指南》的总结和思考中,一系列文章的一篇,目录在这里
TCP链接
TCP是承载HTTP的底层设施,对于前端程序员来说,通常这就是所需要接触和了解的最深的网络层次。
TCP与同为传输层的UDP协议相比,速度较慢(延时更大),因为提供了许多服务:
- 链接性服务: 通过(源IP,源端口,目的IP,目的端口)标示一个链接,不能同时启动2个一样的链接
- 可靠数据传输: 通过校验和与ACK响应来保证数据的无损,有序到达
- 拥塞控制: 通过慢启动和侦测丢包率控制发包速度避免网络堵塞
- 流量控制: 根据窗口大小控制数据速度,防止接收方缓存溢出
理解TCP的开销对理解HTTP性能非常重要
HTTP链接时延
在没有任何优化的情况下,一个HTTP链接需要2个RTT
RTT: Round Trip Time 指从发出请求到收到响应的时间
其中第一个RTT进行TCP前两次握手,第二个RTT完成握手并得到请求的资源
对于包含数十上百个资源的现代Web站点来说,这样巨大的链接开销是无法承受,尤其是链接遥远的网站。因此人们想出了许多优化方法尽量减少链接数:
- 合并JavaScript文件和CSS文件,减少链接请求
- 采用Sprite技术,把所有小图标用Photoshop合为一个大图,利用
background-position
和background-image
定位图片
许多其他的优化技巧参考关于性能优化的文章,显然这些方法笨拙而又局限,因此改进HTTP链接迫在眉睫
HTTP连接性能的改进
现代的浏览器和HTTP连接通常采用下面三种方法,以及他们的混合来提高性能,减少时延
并行连接
当浏览器解析完初始的HTML文档后,可以并行的使用不同端口开启多个FTP连接来获取资源(如之前所述,四元组又一个不同即可),因此我们可以看到多个资源的并行加载(图片等)
主流浏览器(Chrome, Firefox, IE9+)在HTTP/1.1协议下,对于一个域名可以开启最多6个连接
当带宽是主要瓶颈时,并行连接并不会加快响应速度,但是多个资源(图片)的缓慢加载会给用户一种比单个资源挨个加载更快的错觉,因此使用并行链接总是一个好的方法
持久连接
HTTP连接依赖于TCP连接的建立,如果每次HTTP请求新开一条TCP连接,n个请求需要2n RTT,如果保持一条TCP连接发送这些HTTP请求,可以节省 (n-1) 个RTT。
HTTP/1.0 并没有持久连接的选项,因此许多浏览器和服务器自行扩展了许多特性,形成了一个非标准的 HTTP/1.0+ 协议。
HTTP/1.0+ 通过下述策略完成Keep-Alive:
Connection: Keep-Alive
当浏览器请求和服务器响应同时包含该字段,建立持久连接Keep-Alive: max=, timeout=
指定持久策略,max指定接下来的HTTP事物数,timeout指定空闲多久关闭
HTTP/1.0+ 可能会导致一些严重问题,在本文最后部门阐述
HTTP/1.1 中默认采用持久连接,并且不支持Keep-Alive
首部,只有显式指定Connetction: close
可以不使用持久连接。持久连接必须设置正确无误的Content-Length
首部,因为无法通过关闭连接指示报文是否结束
无论是HTTP/1.1 还是 HTTP/1.0+ 的持久连接,服务器都能够随时关闭连接,持久连接不是一个保证的承诺
管道化连接
HTTP/1.1 允许在持久连接的基础上使用管道连接。管道化连接是在得到ACK回复前发送多个请求,基于一个TCP连接发送的多个HTTP请求
管道化不应该用来发送带有副作用的请求,比如POST,避免造成多次影响
Keep-Alive 与 哑代理
之前说到Connection: Keep-Alive
头部可能引起一些严重问题,主要出现在代理服务器上
对于一个代理服务器,如果他不只是单纯的转发每一个字节,不进行任何其他处理,那么他就是一个盲中继。当盲中继转发Keep-Alive
就导致瘫痪,变成一个哑代理
|
|
为避免此类问题,现代代理绝对不能转发Connection
首部和其列出的首部名