4.4、HTML5
在 Web 应用中,浏览器和服务器之间使用的是请求 / 响应的交互模式。浏览器发出请求,服务器根据收到的请求来生成相应的响应,
这种方式的不足之处在于:服务器端产生的数据变化不能及时地通知浏览器,而是需要等到下次请求发出时才能被浏览器获取。对于某些对数据实时性要求很高的应用来说,这种延迟是不能接受的。
目前常见的解决办法有不少,主要可以分成两类:
- 基于 HTTP 协议:简单轮询、COMET 技术、服务器推送事件(HTML 5 新增)
- 基于TCP 协议: WebSocket (HTML 5 新增)
简单轮询
简易轮询的原理非常简单,让浏览器隔个几秒就发送一次请求,询问服务器是否有新信息。
COMET
COMET 技术改进了简易轮询的缺点,使用的是长轮询。长轮询的方式在每次请求时,服务器端会保持该连接在一段时间内处于打开状态,而不是在响应完成之后就立即关闭。这样做的好处是在连接处于打开状态的时间段内,服务器端产生的数据更新可以被及时地返回给浏览器。当上一个长连接关闭之后,浏览器会立即打开一个新的长连接来继续请求。
这种方式也是对简易轮询一个优化,解决了简易轮询数据通知不及时,以及减少了大量的无效轮询次数。缺点:长期占用连接,丧失了无状态高并发的特点。
COMET 技术的实现在服务器端和浏览器端都需要第三方库的支持。并不是 HTML 5 标准的一部分,从兼容标准的角度出发,也不推荐使用.
SSE
服务器推送事件(Server-sent Events)是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端。相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的使用更简单,对服务器端的改动也比较小。对于某些类型的应用来说,服务器推送事件是最佳的选择。主要特点:实现自动重连,服务器数据推送。
text/event-stream :Server-sent Events 规范是 HTML 5 规范的一个组成部分
注意:SSE 是单向通道,只能服务器向客户端发送消息,如果客户端需要向服务器发送消息,则需要一个新的 HTTP 请求。
SSE的java实现
后端实现
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/event-stream");
response.setCharacterEncoding("utf-8");
for (int i = 0; i < 5; i++) {
// 指定事件标识
response.getWriter().write("event:me\n");
// 格式: data: + 数据 + 2个回车
response.getWriter().write("data:" + i + "\n\n");
response.getWriter().flush();
try {
TimeUnit.*SECONDS*.sleep(1);
} catch (InterruptedException e) {
}
}
}
前端实现
<script type="text/javascript">
// 初始化, 参数为url
var sse = new EventSource("ssh/url");
sse.onmessage = function(e) {
console.log("message", e.data, e);
}
// 监听指定事件, (就不会进入onmessage了)
sse.addEventListener("me", function(e) {
console.log("me event", e.data);
// 如果不关闭,会自动重连
if (e.data == 3) {
sse.close();
}
});
</script>
主要参数:
event 消息的事件类型:客户端收到消息时,会在当前的 EventSource 对象上触发一个事件,这个事件的名称就是这个字段的值,如果消息没有这个字段,客户端的 EventSource 对象就会触发默认的 message 事件。
id 这条消息的 ID:客户端接收到消息后,会把这个 ID 作为内部属性 Last-Event-ID,在断开重连 成功后,会把 Last-Event-ID 发送给服务器。
data 消息的数据字段: 客户端会把这个字段解析为字符串,如果一条消息有多个 data 字段,客户端会自动用换行符 连接成一个字符串。
retry 指定客户端重连的时间:只接受整数,单位是毫秒。如果这个值不是整数则会被自动忽略。
SSE 如何保证数据完整性
客户端在每次接收到消息时,会把消息的 id 字段作为内部属性 Last-Event-ID 储存起来。SSE 默认支持断线重连机制,在连接断开时会 触发 EventSource 的 error 事件,同时自动重连。再次连接成功时 EventSource 会把 Last-Event-ID 属性作为请求头发送给服务器,这样服务器就可以根据这个 Last-Event-ID 作出相应的处理。
注意:id 字段不是必须的,服务器有可能不会在消息中带上 id 字段,这样子客户端就不会存在 Last-Event-ID 这个属性。所以为了保证数据可靠,我们需要在每条消息上带上 id 字段。
参考:
SSE:使用 HTTP 做数据推送应用 - V2EX
WebSocket
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。首次通过HTTP协议建立连接之后,接下来就是完全按照Websocket协议进行交互。
参考:
WebSocket 教程 - 阮一峰的网络日志
WebSocket简单介绍 - 肥宅兜 - 博客园
HTTP1.0
HTTP1.0的使用的是短连接,每次请求都需要经过三次握手建立一个TCP连接,四次握手断开连接。
HTTP1.1
HTTP1.1提升性能的手段
1.持久连接 (keep-alive/persistent connection)
2.并行连接
3 流水线(Pipelining)
持久连接
HTTP1.1开始默认建立的是持久连接(有时叫长连接),即一旦浏览器发起HTTP请求,建立的连接不会请求应答之后立刻断掉。一个连接可以不断传输多个HTTP请求,但是如果上一个请求的响应还未收到,则不能处理下一个请求。
注意:在HTTP1.1中默认开启Connection: keep-alive。
并行连接
按照默认设定,一个连接中的每一个请求必须等待收到响应后才能发送下一个请求,所以如果复数的资源请求全部在一个连接one by one发送给服务器显然会很慢,而为了弥补这一缺陷,浏览器通常会默认开启多个TCP连接,然后再根据每个连接的状态在其中依次发送数据请求,而且客户端有权任意关闭超发的连接。
Firefox 2: 2
Firefox 3+: 6
Opera 9.26: 4
Opera 12: 6
Safari 3: 4
Safari 5: 6
IE 7: 2
IE 8: 6
IE 10: 8
Chrome: 6
流水线(Pipelining)
可以在一个连接中发送多个请求不必等待前一个请求返回。但这项技术比较容易踩坑,所以主流面向用户的浏览器,这项技术是被默认关闭。
HTTP1.1存在效率问题
如上面所说,在HTTP1.1中是默认开启了Keep-Alive,他解决了多次连接的问题,但是依然有两个效率上的问题:
- 串行的文件传输。当请求a、b文件时,b文件只能等待,必须等a文件传输完成后,b文件才能传输,独占了网络。
- 连接数过多。我们假设Apache设置了最大并发数为300,因为浏览器限制,浏览器发起的最大请求数为6,也就是服务器能承载的最高并发为50,当第51个人访问时,就需要等待前面某个请求处理完成。
HTTP2
HTTP2.0可以说是SPDY的升级版
HTTP/2有四大特性:二进制格式(Binary Format)、头部压缩、服务端推送(Server Push)、多路复用。
多路复用(MultiPlexing)
即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
服务端推送(server push)
同SPDY一样,HTTP2.0也具有server push功能。目前,有大多数网站已经启用HTTP2.0,例如YouTuBe,淘宝网等网站,利用chrome控制台可以查看是否启用H2。
注意:HTTP/2引入了服务器推送,它使服务器能够主动发送资源到客户端缓存。但是,它并不允许将数据推送到客户端应用程序本身。服务器推送只能由浏览器处理,并且不会在应用程序代码中弹出,这意味着应用程序没有API来获取这些事件的通知。
解决了HTTP1.1存在效率问题
- 问题一:能够把HTTP消息分解成交错的帧,并在另一端组装它们是HTTP/2中一个非常重要的提高。文件传输不再串行,由于所有请求的消息都可分解,那么某一个请求不用等待别一个请求的结束再发送。
- 问题二:HTTP/2对同一域名下所有请求都是基于流,也就是说同一域名不管访问多少文件,也只建立一路连接。同样Apache的最大连接数为300,因为有了这个新特性,最大的并发就可以提升到300,比原来提升了6倍!
参考:
HTTP、HTTP2 - wujiaolong - 博客园
浅析HTTP/2的多路复用 - 奥巴驴 - SegmentFault 思否
Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE-网页端IM开发/专项技术区 - 即时通讯开发者社区!
SSE技术详解:一种全新的HTML5服务器推送事件技术-网页端IM开发/专项技术区 - 即时通讯开发者社区!
代码:
git@github.com:lesline/servlet.git