Springboot + webSocket实现服务器消息推送
WebSocket协议
为什么需要WebSocket协议
因为HTTP协议有一个缺陷:通信只能由客户端发起。
这种单向请求的特点,注定了服务器如果有连续的变化,客户端想要获知就非常麻烦。我们只能用轮询的方式来了解服务器有没有最新的消息。
websocket协议简介
WebSocket协议最大特点就是服务器可以主动向客户端推送消息,客户端也可以主动向服务器发送消息。是服务器推送技术的一种。
对比HTTP协议,WeSocket协议使得长连接变成了一个真正的长连接。通过第一个HTTP request建立了TCP连接之后,之后的交换数据都不需要再发HTTP request。并且和HTTP-keep-alive的区别在于WebSocket协议省去了大量的HTTP-Header信息,使得信息的传输更加的高效。
和传统的服务器推送技术对比
http long poll和ajax轮询都可以实现服务器推送。首先介绍一下long poll和ajax轮询。
ajax轮询的原理非常简单,让浏览器隔几秒就发送一次请求,询问服务器是否有新信息。
long poll原理也是采用轮询的方式,不过和ajax轮询的区别在于采取的是阻塞模型,即客户端发起连接之后,如果没有消息,就一直不返回Response。
上述两种方式都是非常消耗资源的。
- ajax轮询 需要服务器有很快的处理速度和资源。(速度)
- long poll 需要有很高的并发,也就是说同时接待客户的能力。
而web Socket经过一次HTTP请求进行协议升级之后,就可以做到源源不断的信息传送。
WebSocket建立连接
WebSocket协议服用了Http的握手通道,具体指客户端通过HTTP请求与WebSocket服务端协商升级协议。
客户端:申请协议升级
1
2
3
4
5
6
7GET / HTTP/1.1
Host: localhost:8080
Origin: http://127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: w4v7O6xFTi36lq3RNcgctw==重点请求头部意义如下:
Connection: Upgrade
:表示升级协议Upgrade:websocket
:表示要升级到websocket协议Sec-WebSocket-Version
:表示websocket协议的版本,如果服务端不支持该版本,返回一个Sec-WebSocket-Version
Header,包含服务端支持的版本号Sec-WebSocket-Key
:和后面服务端响应首部的Sec-WebSocket-Accept
是配套的,提供最基本的安全保障
服务端:响应升级协议
1
2
3
4
5
6Request URL: ws://localhost:8080/demo/notification/993/r2b4sth6/websocket
Request Method: GET
Status Code: 101
Connection:Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: Oy4NRAQ13jhfONC7bP8dTKb4PTU=服务器返回内容如下,状态码
101
表示协议切换,到此完成协议升级。Sec-WebSocket-Accept
的计算Sec-WebSocket-Accept
根据客户端请求首部的Sec-WebSocket-Key
计算出来。计算公式为:
- 将
Sec-WebSocket-Key
跟258EAFA5-E914-47DA-95CA-C5AB0DC85B11
拼接。 - 通过SHA1计算出摘要,并转成base64字符串。
- 将
数据帧格式
略…
数据传递
略…
连接保持+心跳
WebSocket为了保持客户端,服务端的实时双向通信,需要确保客户端,服务端之间的TCP信道保持连接。
如果客户端和服务端长时间没有数据往来,但是需要保持连接,可以通过心跳来实现。
- 发送方->接收方:ping
- 接收方->发送方:pong
ping、pong的操作,对应的是WebSocket的两个控制帧,opcode
分别是0x9
、0xA
。
SpringBoot+WebSocket+sockjs+stompjs实现服务器推送例子
websocket,sockjs,stompjs三者关系
websocket:是底层协议,基于TCP,可以看作对http协议的一种补充
sockjs: sockjs是一个javascript库,为了应对许多浏览器不支持websocket协议的问题,设计备选了Sockjs。如果websocket不可用,自动降为轮询的方式。
stompjs: Simple Text Oriented Message Protocol
,来为浏览器和server的通信增加适当的语义。
三者关系:websocket是底层协议,sockjs是websocket的备选方案,也是底层协议,而stompjs是基于websocket(sockjs)的上层协议。
- HTTP协议解决了web浏览器发起请求以及web服务器响应请求的细节,假设HTTP协议不存在,只能用TCP套接字来编写web应用。
- 直接使用 WebSocket(SockJS) 就很类似于 使用 TCP 套接字来编写 web 应用,因为没有高层协议,就需要我们定义应用间所发送消息的语义,还需要确保连接的两端都能遵循这些语义。
- 同HTTP在TCP 套接字上添加请求-响应模型层一样,STOMP在WebSocket 之上提供了一个基于帧的线路格式层,用来定义消息语义;
配置websocket服务
1 | package com.shine.websocket.config; |
配置websocket常量
1 | package com.shine.websocket.common; |
定义服务器定时推送任务
1 | package com.shine.websocket.task; |
前端订阅websocket消息推送
1 | <script> |