【问题标题】:websocket client close failed when switch network/ offline切换网络/离线时 websocket 客户端关闭失败
【发布时间】:2022-12-11 17:08:23
【问题描述】:
我想问一些关于如何在离线/切换网络时关闭 websocket 客户端的问题。
当我尝试在 chrome 中关闭 2 案例的套接字时,在我调用 websocket.close 之后,我很长一段时间(大约 60 秒)都无法接收到 onclose 事件,然后我终于可以接收到它了。
查看readystate后,发现在接下来的60s中,state是2(CLOSEING),而不是3(CLOSED)。
所以我想知道在离线/切换网络条件下调用 websocket.close() 时是否遗漏了任何步骤。而在网络正常的情况下运行良好。
【问题讨论】:
标签:
javascript
websocket
offline
readystate
【解决方案1】:
你的后端框架是什么?
如果您尝试处理客户端网络突然掉线的情况,您可以通过以下两种方式尝试从客户端关闭 websocket。
请参考源代码here。
-
使用js离线事件句柄
如果我们想检测用户是否离线,我们只需将 websocket close 函数添加到离线事件函数中。
前端
function closeWebSocket() {
websocket.close();
}
window.on('beforeunload offline', event => {
closeWebSocket();
});
后端(WebSocketServer)
@OnClose
public void onClose(Session session) {
Client client = CURRENT_CLIENTS.get(session.getId());
log.info("onClose. client name: {}", client.getTeamName());
CURRENT_CLIENTS.remove(session.getId());
}
-
在客户端使用 Ping 间隔并减少服务器端的 websocket 会话超时
如果 websocket 服务器在特定时间内没有收到任何消息,则会导致超时。因此,如果客户端由于离线而未发送任何 ping,我们可以使用此机制来减少关闭会话的超时时间。
前端
// send ping to server every 3 seconds
const keepAlive = function (timeout = 20000) {
if (websocket.readyState === websocket.OPEN) {
websocket.send('ping');
}
setTimeout(keepAlive, timeout);
};
后端(WebSocketConfig)
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(5000L);
return container;
}