需求:“客户端扫二维码,将客户端参数信息展现在web端”前端
问题焦点:实时的web应用,Client 跟 Server 之间,实时的双向通讯。react
Client 按期向 Server 发送请求,以此保持与 Server 端数据的同步。典型应用场景:nginx
Ajax技术,局部刷新Web页面git
缺点:github
带宽和 CPU 资源:因为 Client 按期向 Server 发送请求,当 Server 端没有数据更新时,Client仍旧发送请求,这形成带宽的浪费以及Server端CPU的耗费web
实时性:轮询间隔内,会有数据延迟spring
目标:节省带宽,下降无效的网络传输。npm
基本原理:segmentfault
保持链接:HTTP 层,保持链接,Server 接收到 Client 的请求以后,若是没有数据更新,则链接保持一段时间;后端
直到有数据更新或者链接超时,这样能够减小无效的 Client 与 Server 之间的交互;
经过保持链接,减小 Request 和 Response 的数量,节省带宽;
缺陷:
节省带宽,效果有限:HTTP的数据包HEAD部分数据量很大(400+Byte),但真正有效的数据不多(10Byte),这样的数据包在网络中周期传输,浪费带宽。
数据更新频繁场景下,数据实时性:当Server端数据频繁更新时,Server端必须等待下一个请求到来,才能发送更新的数据,这中间的延迟最高为 1.5 x RTT(往返时间)
网路拥塞场景下,等待时间更久,由于须要从新创建链接;
本质缘由:
链接保持:须要从新创建 HTTP 链接(HTTP 1.1 只能缓解,没法从原理上,完全解决)
数据格式:仍然为应用层的数据格式, HTTP HEADER 数据占用比较大
经过 SSE ,客户端能够自动获取数据更新,而不用重复发送HTTP请求。一旦链接创建,“事件”便会自动被推送到客户端。服务器端SSE经过 事件流(Event Stream) 的格式产生并推送事件。
能够实现服务器到客户端的单向数据通讯。
SSE相较于轮询具备较好的实时性,使用方法也很是简便。
缺点:
大并发状况下,服务器可能会宕机。
SSE只支持服务器到客户端单向的事件推送,并且全部版本的IE(包括到目前为止的Microsoft Edge)都不支持SSE。若是须要强行支持IE和部分移动端浏览器,能够尝试 EventSource Polyfill(本质上仍然是轮询)
传统Web中,是由 Browser 主动向 Server 端发送请求,以此得到 Server 端数据;
若是要实现实时通讯,实时获取 Server 端的数据,一般是 Client 端按期发送HTTP请求,Server端进行响应并返回数据;
HTTP协议:基于请求/响应模式的、单向的、无状态的、应用层协议;
HTTP协议为何不容许Server主动向Client推送数据?
若是容许 Server 向 Client 主动推送数据,则 Client 很容易受到攻击;特别是广告商会将广告信息,强行推送给 Client,所以 HTTP 的单向特性是必要的。
WebSocket协议借用HTTP协议的101( switch protocol) 状态码来达到协议转换,切换为WebSocket协议,它自己是基于Tcp协议的。
特色:
Client 跟 Server 之间,双向通讯技术,Client 和 Server,均可以主动发起通讯
是一种网络通讯协议
创建在传输层 TCP 协议之上
优势:
节省带宽;(HTTP 协议的 HEAD 比较大)
节省服务器CPU资源;(HTTP 协议的 Polling 方式,即便 Server 没有数据也要接收 Request)
下图展现了Polling和WebSocket两种模式下,Web应用的效率:
首先,WebSocket是一个持久化的协议,相对于HTTP这种非持久的协议来讲。HTTP的生命周期经过Request来界定,也就是一个Request一个Response,那么在HTTP1.0中,此次HTTP请求就结束了。HTTP1.1进行了改进,可使用keep-alive保持链接,可是仍旧是一个Request = 一个Response, Response显得很是的被动,不能主动发起。
来自客户端的握手信息:
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13复制代码
重点请求首部含义:
Connection: Upgrade:表示要升级协议
Upgrade: websocket:表示要升级到 websocket 协议。
Sec-WebSocket-Version: 13:表示 websocket 的版本。若是服务端不支持该版本,须要返回一个 Sec-WebSocket-Versionheader ,里面包含服务端支持的版本号。
Sec-WebSocket-Key:是一个Base64 encode的值,由浏览器随机生成,与后面服务端响应首部的 Sec-WebSocket-Accept 是配套的,用于服务端校验,提供基本的防御,好比恶意的链接。
Sec_WebSocket-Protocol:是一个用户定义的字符串,用来区分同 URL 下,不一样的服务所须要的协议。
来自服务器的握手信息:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat复制代码
重点响应首部含义:
Sec-WebSocket-Accept 根据客户端请求首部的 Sec-WebSocket-Key 计算出来。
Connection和Upgrade依然是表示协议升级为websocket协议。
WebSocket 客户端、服务端通讯的最小单位是 帧(frame),由 1 个或多个帧组成一条完整的消息(message)。
发送端:将消息切割成多个帧,并发送给服务端;
接收端:接收消息帧,并将关联的帧从新组装成完整的消息;
一旦 WebSocket 客户端、服务端创建链接后,后续的操做都是基于数据帧的传递。
WebSocket的每条消息可能被切分红多个数据帧。当 WebSocket 的接收方收到一个数据帧时,会根据FIN(是数据帧当中的一个标识,用于判断当前帧是否为当前消息的最后一帧)的值来判断,是否已经收到消息的最后一个数据帧。
当接收到消息的最后一帧,便可以对消息进行处理。
不少缘由都会触发链接关闭,通常状况是都会触发链接的onClose事件,可是当断网状况下是不会触发的onclose,这时候就不知道链接是断掉的,此时能够采用心跳重连,客户端每隔一段时间向服务端发送ping数据,服务端一旦苏醒,将进行pong响应,此时便可从新链接。心跳重连不是轮询,轮询会不断创建链接(多个链接),而心跳仍是当前这个链接,只是一直发探测消息而已。
一旦发送或接收到一个Close控制帧,websocket 关闭阶段握手启动。
状态码 |
名称 |
描述 |
---|---|---|
0–999 |
保留段, 未使用. |
|
1000 |
CLOSE_NORMAL |
正常关闭; 不管为什么目的而建立, 该连接都已成功完成任务. |
1001 |
CLOSE_GOING_AWAY |
终端离开, 可能由于服务端错误, 也可能由于浏览器正从打开链接的页面跳转离开. |
1002 |
CLOSE_PROTOCOL_ERROR |
因为协议错误而中断链接. |
1003 |
CLOSE_UNSUPPORTED |
因为接收到不容许的数据类型而断开链接 (如仅接收文本数据的终端接收到了二进制数据). |
1004 |
保留. 其意义可能会在将来定义. |
|
1005 |
CLOSE_NO_STATUS |
保留. 表示没有收到预期的状态码. |
1006 |
CLOSE_ABNORMAL |
保留. 用于指望收到状态码时链接非正常关闭 (也就是说, 没有发送关闭帧). |
1007 |
Unsupported Data |
因为收到了格式不符的数据而断开链接 (如文本消息中包含了非 UTF-8 数据). |
1008 |
Policy Violation |
因为收到不符合约定的数据而断开链接. 这是一个通用状态码, 用于不适合使用 1003 和 1009 状态码的场景. |
1009 |
CLOSE_TOO_LARGE |
因为收到过大的数据帧而断开链接. |
1010 |
Missing Extension |
客户端指望服务器商定一个或多个拓展, 但服务器没有处理, 所以客户端断开链接. |
1011 |
Internal Error |
客户端因为遇到没有预料的状况阻止其完成请求, 所以服务端断开链接. |
1012 |
Service Restart |
服务器因为重启而断开链接. |
1013 |
Try Again Later |
服务器因为临时缘由断开链接, 如服务器过载所以断开一部分客户端链接. |
1014 |
由 WebSocket 标准保留以便将来使用. |
相较于HTTP协议,WebSocket支持持久链接;
服务器与客户端之间交换的标头信息很小,大概只有2字节;
客户端与服务器均可以主动传送数据给对方,真正的全双工;
不用频率建立TCP请求及销毁请求,减小网络带宽资源的占用,同时也节省服务器资源;
WebSocket在用于双向传输、推送消息方面可以作到灵活、简便、高效,但在普通的Request-Response过程当中并无太大用武之地,比起普通的HTTP请求来反倒麻烦了许多,甚至更为低效。好比某些场景只须要简单的Request-Response,若是换作WebSocket还须要增长一个请求标识RequestId,增长成本。每项技术都有自身的优缺点,在适合它的地方能发挥出最大长处,而看到它的几个优势就不分场合地全方位推广的话,可能会拔苗助长。
spring websocket须要tomcat为7.x及以上版本;
websocket的功能支持须要nginx和本机都增长支持websocket协议的配置;
web端页面初始化生成一个惟一标识,标识当前web端页面;
将惟一标识放在二维码的url地址中生成二维码;
app端扫一扫,请求二维码对应的服务,同时这个请求携带了web端页面的惟一标识和app的一些参数信息;
服务端收到请求,将参数进行处理返回给携带了惟一标识的web端页面;
web端组件展现服务端响应的信息;
做者使用的是SpringMVC+React的先后端分离框架,这里推荐几个React不错的插件方便使用:
二维码生成插件:github.com/zpao/qrcode…
Cookie插件:https://www.npmjs.com/package/react-cookies