Open chenqunfeng opened 7 years ago
浏览器发起一个Ajax请求,服务器收到后无论有无新数据,都会立即响应。一次响应结束后,连接断开,在setTimeout时间以后发起另一次Ajax请求。这就是所谓的轮询。
长轮询与轮询的不同之处在与,当没有新数据时,服务器会挂起这个请求,并时不时去查看是否有新数据,直到有新数据时才响应,或者连接超时后自动断开。然后与轮询相同的是,长轮询在得到响应后也会在setTimeout时间以后发起另一次长轮询请求。与轮询相比,减少了无用的轮询,也就是减少了无用的HTTP频繁建立和断开的损耗。
长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。也就是说,利用Connection: keep-alive,在连接超时之前,只建立一次TCP连接实现后续同样的Ajax多次请求都通过这个连接传输,而不需要重复建立连接和断开连接。
在HTTP1.0中,是不支持持久连接的,每个连接都是一次性的,所以HTTP1.0中并不支持长连接;而在HTTP1.1中,增加了持久连接,减少了重复建立连接的损耗。 PS:在现在几乎所有的网址中,几乎所有的请求都会默认带上Connection: keep-alive,这是因为现在的框架都会默认将keep-alive开启,虽然会导致原本是短连接的请求都变成了长连接,但是在server内存足够的情况下,一般影响都不大。所以,也因为这个原因,现在我们使用的轮询基本都是长连接。
不开启keep-alive的情况下的同个Ajax请求,我们可以看到每一次都重新建立了连接。
开启keep-alive的情况下的同个Ajax请求,我们可以看到,除了第一次请求以外,在超时时间内的后续请求,都无需重复建立请求,而是都通过第一次建立的连接进行传输。
HTTP协议属于拉取协议,所以正常情况下服务器无法主动向客户端推送消息。不过,有一种变通的方法,就是服务器向客户端推送流消息(stream),像视频那样,在视频下载完毕之前,源源不断往客户端推送流消息,客户端也不会关闭连接。 SSE就是利用这种机制,让服务器向客户端推送流消息。而SSE也是基于HTTP协议,目前除了IE/Edge不支持之外其他都支持,默认支持断线重连,一般都是用来传送文本,二进制数据需要编码后传送。
var source = new EventSource(url); source.onopen = function (event) { console.log('Connection open ...'); }; source.onerror = function (event) { console.log('Connection close.'); }; source.addEventListener('chatStream', function (event) { console.log('firstChat: ' + event.data); }); source.onmessage = function (event) { console.log('message: ' + event.data); };
// 纯node实现 var http = require("http"); http.createServer(function (req, res) { var fileName = req.url; if (fileName === "/chat") { res.writeHead(200, { "Content-Type":"text/event-stream", "Cache-Control":"no-cache", "Connection":"keep-alive", "Access-Control-Allow-Origin": '*', }); res.write("event: chatStream\n"); res.write("data: Hi \n\n"); interval = setInterval(function () { res.write("data: Hello \n\n"); }, 1000); req.connection.addListener("close", function () { clearInterval(interval); res.end(); }, false); } }).listen(3000);
// express实现且使用了compression中间件 router.get('/chat', function(req, res, next) { res.set({ "Content-Type":"text/event-stream", "Cache-Control":"no-cache", "Connection":"keep-alive", "Access-Control-Allow-Origin": '*', }); res.write("event: chatStream\n"); res.write('data: Hi \n\n'); res.flush(); interval = setInterval(function () { res.write('data: Hello \n\n'); res.flush(); }, 2000); req.connection.addListener("close", function () { clearInterval(interval); res.end(); }, false); })
WebSocket是HTML5新出的协议,是一种基于TCP之上的客户端与服务器全双工通讯的协议,不属于HTTP协议,也和HTTP没有关系。它属于持久化协议,这一点与非持久化的HTTP协议有很大不同。
轮询
浏览器发起一个Ajax请求,服务器收到后无论有无新数据,都会立即响应。一次响应结束后,连接断开,在setTimeout时间以后发起另一次Ajax请求。这就是所谓的轮询。
长轮询
长轮询与轮询的不同之处在与,当没有新数据时,服务器会挂起这个请求,并时不时去查看是否有新数据,直到有新数据时才响应,或者连接超时后自动断开。然后与轮询相同的是,长轮询在得到响应后也会在setTimeout时间以后发起另一次长轮询请求。与轮询相比,减少了无用的轮询,也就是减少了无用的HTTP频繁建立和断开的损耗。
长连接
长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。也就是说,利用Connection: keep-alive,在连接超时之前,只建立一次TCP连接实现后续同样的Ajax多次请求都通过这个连接传输,而不需要重复建立连接和断开连接。
HTTP1.0和HTTP1.1的支持情况
在HTTP1.0中,是不支持持久连接的,每个连接都是一次性的,所以HTTP1.0中并不支持长连接;而在HTTP1.1中,增加了持久连接,减少了重复建立连接的损耗。 PS:在现在几乎所有的网址中,几乎所有的请求都会默认带上Connection: keep-alive,这是因为现在的框架都会默认将keep-alive开启,虽然会导致原本是短连接的请求都变成了长连接,但是在server内存足够的情况下,一般影响都不大。所以,也因为这个原因,现在我们使用的轮询基本都是长连接。
请求响应中不开启keep-alive
不开启keep-alive的情况下的同个Ajax请求,我们可以看到每一次都重新建立了连接。
请求响应中开启keep-alive
开启keep-alive的情况下的同个Ajax请求,我们可以看到,除了第一次请求以外,在超时时间内的后续请求,都无需重复建立请求,而是都通过第一次建立的连接进行传输。
SSE(Server-Sent Events)
HTTP协议属于拉取协议,所以正常情况下服务器无法主动向客户端推送消息。不过,有一种变通的方法,就是服务器向客户端推送流消息(stream),像视频那样,在视频下载完毕之前,源源不断往客户端推送流消息,客户端也不会关闭连接。 SSE就是利用这种机制,让服务器向客户端推送流消息。而SSE也是基于HTTP协议,目前除了IE/Edge不支持之外其他都支持,默认支持断线重连,一般都是用来传送文本,二进制数据需要编码后传送。
SSE图示
SSE具体实现
客户端
服务端(node)
说明
WebSocket
WebSocket是HTML5新出的协议,是一种基于TCP之上的客户端与服务器全双工通讯的协议,不属于HTTP协议,也和HTTP没有关系。它属于持久化协议,这一点与非持久化的HTTP协议有很大不同。
握手阶段
帧协议