WebSocket 是一种网络传输协议,可在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket 协议在 2011 年由 IETF 标准化为 RFC 6455,后由 RFC 7936 补充规范。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。
上面是百科对于WebSocket
的一个解释,在早些时候或者一些传统项目上做站内推送
或者消息通知
等逻辑都是通过短轮询
来实现的。也就是浏览器客户端定时的去请求服务端获取最新的通知结果返回客户端
。
但是短轮询的缺点也很明显,HTTP的请求本来就是`一次请求一次响应`,请求跟响应都会带有比较长的`请求/响应头`,但是因为`一次请求一次响应`的设计每次的请求又不可避免的重复带有`请求/响应头`,而真正的传输数据又很少,从而浪费了很多的带宽资源。
天下苦其久矣
,这时候需要有一位猛士来解决这个问题,于是HTML5
定义了WebSocket
协议,跟上面百科的解释一样WebSOcket
只需要一次握手
的设计让每次消息的传递不需要再带上请求/响应头
,非常节省服务器资源和带宽,并且基于长链接
的形式和服务端可以主动向客户端推送数据
的设计让WebSocket能够更实时地进行通讯。
WebSocket有两种资源标识符(URI)
ws无法对应Https协议
。wss是ws基于TLS的安全传输
。并且WebSocket 与 HTTP 和 HTTPS 使用相同的 TCP 端口,可以绕过大多数防火墙的限制。
WebSocket
通讯要先建立连接,这样WebSocket
就成为了一种有状态的协议,后续的通讯也就无需每次传递部分状态信息,节省资源。HTTP
下的轮询操作有一定轮询时间的滞后,WebSocket
建立的双工协议
让服务器可以随时主动给客户端下发数据,响应时间更快,不需要客户端触发。说千遍万遍不如做一遍
创建工程会吧,使用 start.spring.io 自动创建一个demo工程
加入pom文件的WebSocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.1.18.RELEASE</version>
</dependency>
编写WebSocket
的配置类,使其交由Spring
管理
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
Server
类需要注解ServerEndpoint
标明为WebSocket的服务,由此就可通过注解配置的地址进行建立连接和通讯
@OnOpen注解为客户端建立连接时触发的方法
@Slf4j
@Component
@ServerEndpoint("/api/websocket")
public class WebSocketServer {
@OnOpen
public void onOpen(Session session){
log.info("客户端建立连接:{}",session);
}
}
在工程的resources->static
目录下建立一个index.html
页面,代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window) {
websocket = new WebSocket("ws://127.0.0.1:8080/api/websocket");
} else {
alert('当前浏览器 Not support websocket')
}
</script>
</html>
启动项目,访问地址:http://127.0.0.1:8080/index.html
可以打Debug
查看是否触发了onOpen
方法,也可以查看控制台日志是否出现了客户端建立链接
日志
如上图WebSocket
链接就建立成功了
建立连接后当然要发消息了,发消息则是WebSocket
的send
函数
在页面设置一个输入框和按钮,输入框写入信息,按钮触发WebSocket
的send
事件推送消息,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="text" id="message"></in>
<button onclick="send()">发送</button>
</body>
<script>
var websocket = null;
//判断当前浏览器是否支持WebSocket
if('WebSocket' in window) {
websocket = new WebSocket("ws://127.0.0.1:8080/api/websocket");
} else {
alert('当前浏览器 Not support websocket')
}
function send() {
var message = document.getElementById("message").value;
websocket.send(message);
}
</script>
</html>
后端非常简单,增加@OnMessage
注解方法来接受消息
@OnMessage
public void onMessage(String message,Session session){
log.info("客户端:{},接受到消息:{}",session.getId(),message);
}
重启服务,页面如下
链接建立
测试发送一段消息
查看控制台日志
再开一个浏览器Tab页会新建立一个WebSocket的连接,也可以发送消息,如下图