对WebSocket的支持
作为一款现代化应用,我们的框架同样提供了对WebSocket的支持。
通过WebSocket,您可以轻松实现如聊天应用、实时数据推送等多种实时交互功能。
服务间通信
NOTE
在设计我们的框架时,我们秉承了轻量化的理念,特别采用了Redis的发布订阅机制来高效处理Socket服务端与Admin业务端之间的多节点通信问题。
这种机制不仅简化了架构,还提高了系统的可扩展性和响应速度。通过Redis的发布订阅功能,我们可以轻松实现消息的快速分发,从而确保不同节点之间的实时同步。
关键要点:
- sz-service-websocket 服务提供的是基础的WebSocket通讯能力。
- 具体的业务逻辑和功能实现需要根据您的具体业务需求来开发和完善。
通过这种方式,您可以灵活地构建自己的实时通信系统,同时保持系统的轻量和高效。
启用WebSocket通讯
要使WebSocket通讯功能生效,请按照以下步骤进行配置:
步骤一:启动sz-service-websocket
服务
请确保sz-service-websocket
服务已经启动,以便WebSocket连接可以正常建立。
步骤二:配置前端WebSocket连接
在前端项目的.env
文件中,设置WebSocket服务器的连接地址:
## 启用WebSocket通讯
## 要激活WebSocket连接,请将VITE_SOCKET_URL设置为一个有效的WebSocket服务器地址。
## 如果不设置或留空此变量,WebSocket功能将保持禁用状态。示例配置如下:
VITE_SOCKET_URL=ws://127.0.0.1:9993/socket
TIP
WebSocket的协议与HTTP、HTTPS类似:WS对应HTTP,WSS对应HTTPS。确保根据你的安全需求选择合适的协议。
鉴权
我们通过JWT对WebSocket连接进行验证,以确保用户的有效性。
API演示
框架提供了开箱即用的全体推送和定向推送功能[1]。
后端代码:
...
@PostMapping("push/all")
@Operation(summary = "全体推送-升级公告(socket)")
public ApiResult sendUpgradeMsg() {
SocketBean bean = new SocketBean<>();
bean.setData("【全体推送】 系统即将进行升级,预计需要几分钟时间。请您稍等片刻,感谢您的耐心等待");
bean.setChannel(SocketChannelEnum.UPGRADE_CHANNEL);
bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
TransferMessage msg = new TransferMessage();
msg.setMessage(bean);
msg.setFromUser("system");
msg.setToPushAll(true);
websocketRedisService.sendServiceToWs(msg);
return ApiResult.success();
}
@PostMapping("push/user")
@Operation(summary = "定向推送-升级公告(socket)")
public ApiResult sendMsg() {
SocketBean bean = new SocketBean<>();
bean.setData("【定向推送】 系统即将进行升级,预计需要几分钟时间。请您稍等片刻,感谢您的耐心等待");
bean.setChannel(SocketChannelEnum.UPGRADE_CHANNEL);
bean.setScope(MessageTransferScopeEnum.SOCKET_CLIENT);
TransferMessage msg = new TransferMessage();
msg.setMessage(bean);
msg.setFromUser("system");
msg.setToPushAll(false);
List<String> toUsers = new ArrayList<>();
toUsers.add("1"); // 向 loginId = 1 的用户推送消息。既 admin 账号
msg.setToUsers(toUsers);
websocketRedisService.sendServiceToWs(msg);
return ApiResult.success();
}
...
前端代码:
...
const _onMessage = (event: MessageEvent) => {
const { data } = event;
const userStore = useUserStore();
const authStore = useAuthStore();
try {
const res = JSON.parse(data);
switch (res.channel) {
case CHANNEL_DEFAULT:
console.log('接收到socket消息', res)
break;
case CHANNEL_KICK_OFF:
close();
// 1.清除 Token
userStore.clear();
authStore.clear();
ElMessageBox.alert('您已经被强制踢下线了!', '温馨提示', {
confirmButtonText: '确定',
type: 'warning',
callback: () => {
// 2.重定向到登陆页
router.replace(LOGIN_URL);
}
});
break;
case UPGRADE_CHANNEL:
...
break;
default:
mittBus.emit(`socket.${res.channel}`, res.data);
}
console.log('接收到的消息:', res);
} catch (e) {
/* empty */
}
};
...
WebSocket与Service间的通信桥梁:WebsocketRedisService
我们的框架提供了WebsocketRedisService
类,它利用Redis的发布订阅机制,实现了WebSocket服务端与Admin业务端之间的高效通信。以下是该服务的两个核心方法,用于处理不同方向的消息透传:
方法1:sendWsToService(TransferMessage transferMessage)
此方法用于将消息从WebSocket客户端透传至后端服务。通过Redis的发布订阅机制,我们可以确保消息能够快速且准确地传递给后端服务进行处理。
public void sendWsToService(TransferMessage transferMessage) {
redisTemplate.convertAndSend(GlobalConstant.WS_TO_SERVICE, transferMessage);
}
方法2:sendServiceToWs(TransferMessage transferMessage)
此方法用于将消息从后端服务透传回WebSocket客户端。这样,后端服务处理的结果可以实时反馈给前端用户,实现双向通信。
public void sendServiceToWs(TransferMessage transferMessage) {
redisTemplate.convertAndSend(GlobalConstant.SERVICE_TO_WS, transferMessage);
}
使用指南:
- 发送消息:通过调用
sendWsToService
或sendServiceToWs
方法,您可以轻松地在WebSocket客户端和后端服务之间传递消息。 - 自定义消息处理:您可以根据业务需求,自定义
TransferMessage
对象,以包含所需的数据和指令。
通过这种方式,WebsocketRedisService
不仅简化了消息传递的复杂性,还提高了系统的响应速度和可靠性。您可以根据自己的业务逻辑,灵活地使用这些方法来实现实时通信和数据处理。
优雅停机
当 WebSocket 服务停止时,会进行优雅的停机操作。首先,清理 Redis 中的缓存,然后断开所有 WebSocket 连接。只有在这些任务完成后,服务才会完全退出。服务启动时,Web 客户端会根据策略自动重连。
Nginx 配置建议
为了确保 Websocket 连接的稳定性,我们建议对 Nginx 配置进行以下优化:
Websocket 超时时间延长
在 Nginx 配置文件中,找到或添加以下 server
块:
server {
...
# Websocket 支持配置
location /socket {
proxy_pass http://sz-service-websocket:9993; # 后端 WebSocket 服务器地址
proxy_http_version 1.1; # 启用 HTTP/1.1 以支持 WebSocket
proxy_set_header Upgrade $http_upgrade; # 通知 Nginx 转发 Upgrade 头
proxy_set_header Connection "upgrade"; # 通知 Nginx 转发 Connection 头
proxy_set_header Host $host; # 转发 Host 头
# 绕过缓存,因为 Websocket 连接不需要缓存
proxy_cache_bypass $http_upgrade;
# 设置 Websocket 连接的读取和发送超时时间
proxy_read_timeout 3600s; # 1小时
proxy_send_timeout 3600s; # 1小时
}
...
}
说明:
- 请将
http://sz-service-websocket:9993
替换为您实际的后端 WebSocket 服务器地址。 proxy_read_timeout
和proxy_send_timeout
设置为3600s
,即 1 小时,以适应长时间运行的 Websocket 连接。
演示接口位于sz-service-admin服务的 TestController类中。 ↩︎