长连接和短连接
早期 HTTP/1.0 性能上的一个很大的问题,一旦web服务器向浏览器发送了请求报文并且得到相应报文后,他就要关闭TCP连接,这就是HTTP短连接;
那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无畏的 TCP 连接建立和断开,增加了通信开销;
为了解决上述 TCP 连接问题,HTTP/1.1 提出了长连接的通信方式,也叫持久连接(persistent connection)、长连接;
持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态,这样浏览器就可以继续通过相同的 TCP 连接发送请求,保持连接减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载,还节约了网络带宽;
如果浏览器或者服务器在其头信息加入了Connection:keep-alive,则TCP连接在发送后仍将保持打开状态;
Connection 可以为如下两个值:
- Connection: keep-alive (默认值)
- Connection: close
请求报文中:
- close:告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了; 当客户端再次发送Request,需要重新建立TCP连接;
- keep-alive:告诉WEB服务器或者代理服务器,在完成本次请求的响应后,保持连接,等待本次连接的后续请求;
Keep-Alive 字段:如果浏览器请求保持连接,则Keep-Alive 字段表明希望 WEB 服务器保持连接多长时间(秒);
例如:Keep-Alive:300
目前主流浏览器都会在请求头里面包含Connection:keep-alive字段,浏览器会将建立的连接缓存起来,当在有限时效内有再次对相同服务器发送请求时则直接从缓存中取出连接进行通信;当然被缓存的连接如果空闲时间超过了设定值(如firefox为115s,IE为60s)则会关闭连接;
响应报文中:
- close:连接已经关闭;
- keep-alive:连接保持着,在等待本次连接的后续请求;
注意:
- HTTP1.0默认是短连接,即传输完数据就会自动断开,可以使用Connection: keep-alive启用长连接;
- HTTP1.1默认是长连接,即传输完数据不会自动断开,可以使用Connection: close关闭长连接;
长连接存在的问题
长连接也叫持续连接,短连接也叫非持续连接;
对于非持续连接,程序可以通过连接是否关闭来界定请求或响应实体(即报文主体)的边界;即若客户端和服务器之间不是持久连接,程序就不需要知道它正在读取的主体的长度,而只需要读到 TCP 关闭连接为止;
而对于持续连接,这种方法显然不奏效;有时,尽管我已经发送完所有数据,但浏览器并不知道这一点,它无法得知这个打开的连接上是否还会有新数据进来,只能傻傻地等了;
用Content-length解决:
计算实体长度,并通过头部告诉对方,程序可以通过 Content-Length 的长度信息,判断出实体内容已结束;
Content-length引入的新问题:
由于 Content-Length 字段必须真实反映实体长度,但是对于动态生成的内容来说,在内容创建完之前,长度是不可知的;这时候要想准确获取长度,只能开一个足够大的buffer,等内容全部生成好再计算;但这样做一方面需要更大的内存开销,另一方面也会让客户端等更久;
我们需要一个新的机制:不依赖头部的长度信息,也能知道实体的边界,分块编码(Transfer-Encoding: chunked)(数据分块传输)为这种困难提供了解决方案;