我搜索了很多并且无法找到这个:有没有办法让一个spring websocket stomp服务器可以根据sessionId断开客户端(或者真的基于任何东西)?
在我看来,一旦客户端连接到服务器,就没有任何东西允许服务器断开客户端。
答案 0 :(得分:13)
实际上使用一些变通办法可以达到你想要的效果。 为此你应该这样做:
我已经创建了示例spring-boot项目,以展示我们如何从服务器端断开客户端会话: https://github.com/isaranchuk/spring-websocket-disconnect
答案 1 :(得分:4)
您还可以通过实施自定义WebSocketHandlerDecorator
:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig<S extends ExpiringSession> extends AbstractSessionWebSocketMessageBrokerConfigurer<S> {
@Override
public void configureWebSocketTransport(final WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
@Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
@Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
session.close(CloseStatus.NOT_ACCEPTABLE);
super.afterConnectionEstablished(session);
}
};
}
});
super.configureWebSocketTransport(registration);
}
@Override
protected void configureStompEndpoints(final StompEndpointRegistry registry) {
registry.addEndpoint("/home")
.setHandshakeHandler(new DefaultHandshakeHandler(
new UndertowRequestUpgradeStrategy() // If you use undertow
// new JettyRequestUpgradeStrategy()
// new TomcatRequestUpgradeStrategy()
))
.withSockJS();
}
}
答案 2 :(得分:1)
据我所知,API没有提供您要查找的内容,在服务器端您只能检测断开连接事件。如果你想断开某个客户端,我认为你必须采取一些小问题,例如这一个:
解决方法有点麻烦,但它可以正常工作。
答案 3 :(得分:1)
首先,您必须通过继承将一个类作为User类引入,然后像这样使用它:
if (userObject instanceof User) {
User user = (User) userObject;
if (user.getId().equals(userDTO.getId())) {
for (SessionInformation information : sessionRegistry.getAllSessions(user, true)) {
information.expireNow();
}
}
}
答案 4 :(得分:1)
我依靠@DánielKis的想法,并实现了websocket会话管理,其关键点是在类似Singleton的对象中存储供经过身份验证的用户使用的websocket会话。
// WebSocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureWebSocketTransport(WebSocketTransportRegistration registration) {
registration.addDecoratorFactory(new WebSocketHandlerDecoratorFactory() {
@Override
public WebSocketHandler decorate(final WebSocketHandler handler) {
return new WebSocketHandlerDecorator(handler) {
@Override
public void afterConnectionEstablished(final WebSocketSession session) throws Exception {
// We will store current user's session into WebsocketSessionHolder after connection is established
String username = session.getPrincipal().getName();
WebsocketSessionHolder.addSession(username, session);
super.afterConnectionEstablished(session);
}
};
}
});
}
}
用于存储Websocket用户会话的类 WebsocketSessionHolder 。我使用“同步”块来确保线程安全。实际上,此块并不是昂贵的操作,因为不经常使用每种方法(addSession和closeSessions)(在建立和终止连接时)。这里不需要使用ConcurrentHashMap或SynchronizedMap,因为我们在这些方法中对列表执行了很多操作。
// WebsocketSessionHolder.java
public class WebsocketSessionHolder {
static {
sessions = new HashMap<>();
}
// key - username, value - List of user's sessions
private static Map<String, List<WebSocketSession>> sessions;
public static void addSession(String username, WebSocketSession session)
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions == null)
userSessions = new ArrayList<WebSocketSession>();
userSessions.add(session);
sessions.put(username, userSessions);
}
}
public static void closeSessions(String username) throws IOException
{
synchronized (sessions) {
var userSessions = sessions.get(username);
if (userSessions != null)
{
for(var session : userSessions) {
// I use POLICY_VIOLATION to indicate reason of disconnecting for a client
session.close(CloseStatus.POLICY_VIOLATION);
}
sessions.remove(username);
}
}
}
}
最后一步-终止(断开连接)指定的用户Websocket会话(在示例中为“ ADMIN”),例如在某些控制器中
//PageController.java
@Controller
public class PageController {
@GetMapping("/kill-sessions")
public void killSessions() throws Exception {
WebsocketSessionHolder.closeSessions("ADMIN");
}
}
答案 5 :(得分:0)
如果是xml配置,您可以在<websocket:decorator-factories>
的{{1}}中使用<websocket:transport>
。
创建实现<websocket:message-broker>
方法的自定义WebSocketHandlerDecorator
和WebSocketHandlerDecoratorFactory
。
答案 6 :(得分:0)
这似乎很简短,但是我不确定您的情况下实现的样子。但是,我认为在某些情况下需要采取这种解决方法/解决方案:
@Bean
public ServletServerContainerFactoryBean websocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxSessionIdleTimeout(MAX_SESSION_IDLE_TIMEOUT);
return container;
}
当然,如果您想立即断开连接,这似乎不是一个合适的解决方案。但是,如果您只是想减少活动连接的数量,则ping / pong可能是一个不错的选择,因为它仅在主动发送消息时才保持会话打开,从而防止会话过早关闭。