WebSocket 实现后端消息推送
前后端环境:Spring Boot@2.7.x + Vue@2.x
WebSocket 概念
HTTP 协议是一种无状态的、无连接的、单向的应用层协议。它采用了请求/响应模型。通信请求只能由客户端发起,服务端对请求做出应答处理。
这种通信模型有一个弊端:HTTP 协议无法实现服务器主动向客户端发起消息。
这种单向请求的特点,注定了如果服务器有连续的状态变化,客户端要获知就非常麻烦。大多数 Web 应用程序将通过频繁的异步 JavaScript 和 XML(AJAX)请求实现长轮询。轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开)。
WebSocket 就是这样发明的。WebSocket 连接允许客户端和服务器之间进行全双工通信,以便任一方都可以通过建立的连接将数据推送到另一端。WebSocket 只需要建立一次连接,就可以一直保持连接状态。这相比于轮询方式的不停建立连接显然效率要大大提高。
服务端集成
加入 Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
<version>2.4.3</version>
</dependency>
WebSocketConfig.java
/*** imports ***/
/**
* WebSocket 配置类
*/
@Configuration
@EnableWebSocket
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注册一个 /notification 端点,前端通过这个端点进行连接
registry.addEndpoint("/notification")
// 解决跨域问题
.setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 定义了一个客户端订阅地址的前缀信息,也就是客户端接收服务端发送消息的前缀信息
registry.enableSimpleBroker("/topic");
}
}
WebSocketTask.java
/*** imports ***/
/**
* 服务器定时推送任务
*/
@Slf4j
@Component
public class WebSocketTask {
@Autowired
private SimpMessagingTemplate wsTemplate;
@Autowired
private ReceiverDataService receiverDataService;
/**
* 按照标准时间来算,每隔 2s 执行一次
*/
// @Scheduled(cron = "0/10 * * * * ?")
public void websocket() throws Exception {
log.info("【推送消息】开始执行:{}", DateUtil.formatDateTime(new Date()));
// destination, payload
wsTemplate.convertAndSend("/topic/receiver", "message content");
log.info("【推送消息】执行结束:{}", DateUtil.formatDateTime(new Date()));
}
}
客户端集成
引入 sock.js
和 stomp.js
<!-- WebSocket -->
<script src="static/js/sockjs.min.js"></script>
<script src="static/js/stomp.js"></script>
修改 vue 文件
<template>
<!-- ... -->
</template>
<script>
const wsHost = "http://localhost:8081/notification"
const wsTopic = "/topic/receiver"
export default {
name: '',
data() {
return {
// stomp.js
isConnected: false,
stompClient: {},
socket: {},
receiveData: {},
receiverSize: 0
}
},
mounted() {
this._initSockJs()
},
beforeDestroy() {
this._destroySockJs()
},
methods: {
// stomp.js
_initSockJs() {
this.socket = new SockJS(wsHost)
this.stompClient = Stomp.over(this.socket)
this.stompClient.connect({}, frame => {
console.log('WebSocket 连接成功:' + frame)
this.isConnected = true
// Message.success('WebSocket 服务器连接成功')
// 另外再注册一下消息推送
this.stompClient.subscribe(wsTopic, res => {
console.log(JSON.parse(res.body))
})
})
},
_destroySockJs() {
if (this.stompClient != null) {
this.stompClient.disconnect()
this.socket.onclose
this.socket.close()
this.stompClient = {}
this.socket = {}
this.isConnected = false
}
// Message.warning('WebSocket 断开成功!')
console.log('WebSocket 断开成功!')
}
}
}
</script>
<style />
WebSocket 实现后端消息推送
http://lpxz.work/posts/56834/