什么是SockJS
SockJS是一个JavaScript库,提供跨浏览器JavaScript的API,创建了一个低延迟、全双工的浏览器和web服务器之间通信通道。
SockJS是用来干什么的
首先我们要了解一下 --webSocket--
- 前端和后端的交互模式最常见的就是前端发数据请求,从后端拿到数据后展示到页面中。如果前端不做操作,后端不能主动向前端推送数据,这恰恰就是http协议的缺陷。但在我们平常开发中,常遇到客户端需要实时获取服务端信息,做到客户端与服务端互通有无,通过http协议实现(轮询)存在一定延时性,且会造成资源的很大浪费,websocket却能完美实现。恰巧最近有项目需求,就做了一定研究,特此记录。
- 而有因为一些浏览器中缺少对WebSocket的支持,因此,回退选项是必要的,而Spring框架提供了基于SockJS协议的透明的回退选项。SockJS的一大好处在于提供了浏览器兼容性。优先使用原生WebSocket,如果在不支持websocket的浏览器中,会自动降为轮询的方式。
除此之外,spring也对socketJS提供了支持。
如果代码中添加了withSockJS()如下,服务器也会自动降级为轮询。
registry.addEndpoint("/coordination").withSockJS();
- SockJS的目标是让应用程序使用WebSocket API,但在运行时需要在必要时返回到非WebSocket替代,即无需更改应用程序代码。SockJS是为在浏览器中使用而设计的。它使用各种各样的技术支持广泛的浏览器版本。对于SockJS传输类型和浏览器的完整列表,可以看到SockJS客户端页面。
传输分为3类:WebSocket、HTTP流和HTTP长轮询(按优秀选择的顺序分为3类)
sockjs-client
SockJS模仿WebSockets API,但它不是WebSocket,而是一个SockJS Javascript对象。首先,您需要加载SockJS JavaScript库。例如,你可以把它放在你的HTML head里:
<script src="https://cdn.bootcss.com/sockjs-client/1.0.0/sockjs.min.js"></script>
(如果有错误提示可以更换版本号!!!)
sockjs-client建立连接
加载脚本后,你可以建立与SockJS服务器的连接(下面这个是我自己项目中的例子)
// 创建一个有SockJs包装过的webSocket
var socket = new SockJS(`/dorm/websocket`);
//StompJS 简单流文本定向消息协议
stompClient = Stomp.over(socket);
// 发送频率
stompClient.heartbeat.outgoing = 20000;
// client will send heartbeats every 20000ms
// 接收频率
stompClient.heartbeat.incoming = 0;
stompClient.connect({}, function (frame) {
// setConnected(true);
// 订阅和接受消息
stompClient.subscribe("/topic/message/" + dormId, function (response) {
var xx = JSON.parse(response.body);
personList.push(xx);
});
});
接下来就解释一下具体该如何使用
sockjs-client构造函数的参数
var sockjs = new SockJS(url, _reserved, options);
url:后端提供的消息推送的接口
options是一个散列,它可以包含:
1.server: 类型String,默认值-随机4位数字,其会被添加到url上作为实际数据连接。
2.transports: 类型字符串或者字符串数组。此选项允许您提供可由SockJS使用的列表传输。默认情况下,所有可用的传输都将被使用,但有时需要禁用一些回退传输是有用的。
2.sessionId: 类型number或者function。客户端和服务器都使用会话标识符来区分连接。如果将这个选项指定为一个数字,那么SockJS将使用它的随机字符串生成器函数来生成一个N字符长的会话id(其中N对应于sessionId指定的数字)。当您将此选项指定为函数时,函数必须返回一个随机生成的字符串。每次SockJS需要生成一个会话id时,它将调用该函数并直接使用返回的字符串。如果没有指定此选项,默认情况是使用默认的随机字符串生成器生成8个字符的长会话id。
我们再来说说例子中的Stomp是干什么用的
STOMP:即简单(流)文本定向消息协议。用于连接到企业消息代理,它被设计用于处理常用消息传递模式的最小功能子集,STOMP可以用于任何可靠的双向流网络协议,如TCP和WebSocket,虽然STOMP是一个面向文本的协议,但消息payload可以是文本或二进制。就像HTTP在TCP套接字之上添加了请求-响应模型层一样,STOMP 在 WebSocket 之上提供了一个基于帧的线路格式(frame-based wire format)层,用来定义消息的语义。STOMP是一种为MOM(Message Oriented Middleware,面向消息的中间件)设计的简单文本协议,它提供一个可互操作的连接格式,允许客户端与任意STOMP消息代理(Broker)进行交互,用于client之间进行异步消息传输的简单文本协议。
Stomp.over
浏览器提供了不同的WebSocket的协议,一些老的浏览器不支持WebSocket的脚本或者使用别的名字。默认下,stomp.js会使用浏览器原生的WebSocket class去创建WebSocket。利用Stomp.over(ws)这个方法可以使用其他类型的WebSockets。这个方法得到一个满足WebSocket定义的对象。
例如,可以使用由SockJS实现的Websocket:
首先引入这个js
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
var ws = new SockJS(url);
var client = Stomp.over(ws);
...
</script>
如果使用原生的Websockets就使用Stomp.client(url),如果需要使用其他类型的Websocket(例如由SockJS包装的Websocket)就使用Stomp.over(ws)。
除了初始化有差别,Stomp API在这两种方式下是相同的。
client.heartbeat.outgoing/incoming(心跳检测)
客户端client对象有一个字段 heartbeat ,通过改变incoming和outgoing数值,来配置心跳频率(默认频率值为:10000ms)
client.heartbeat.outgoing = 20000; // 客户端每20000ms发送一次心跳检测
client.heartbeat.incoming = 0; // client不接收serever端的心跳检测
client.connect
Stomp 客户端建立了,必须调用它的connect()方法去连接,从而Stomp服务端进行验证。这个方法需要两个参数,用户的登录和密码凭证。
这种情况下,客户端会使用Websocket打开连接,并发送一个CONNECT frame。
这个连接是异步进行的:你不能保证当这个方法返回时是有效连接的。为了知道连接的结果,你需要一个回调函数。
connect()方法可接受不同数量的参数来提供简单的API:
client.connect(login, passcode, connectCallback);
client.connect(login, passcode, connectCallback, errorCallback);
client.connect(login, passcode, connectCallback, errorCallback, host);
Subscribe(订阅)和receive(接收)消息
为了在浏览器中接收消息,STOMP客户端必须先订阅一个目的地destination。
你可以使用subscribe()去订阅。这个方法有2个必需的参数:目的地(destination),回调函数(callback);还有一个可选的参数headers。其中destination是String类型,对应目的地,回调函数是伴随着一个参数的function类型(如图中示例)!