如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息?
Posted
技术标签:
【中文标题】如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息?【英文标题】:How to send ERROR message to STOMP clients with Spring WebSocket? 【发布时间】:2016-02-17 21:55:14 【问题描述】:我正在使用 Spring 的 STOMP over WebSocket 实现和功能齐全的 ActiveMQ 代理。当用户SUBSCRIBE
到某个主题时,有一些权限逻辑,他们必须通过才能成功订阅。我正在使用 ChannelInterceptor 来应用权限逻辑,配置如下:
WebSocketConfig.java:
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
@Override
public void registerStompEndpoints(StompEndpointRegistry registry)
registry.addEndpoint("/stomp")
.setAllowedOrigins("*")
.withSockJS();
@Override
public void configureMessageBroker(MessageBrokerRegistry registry)
registry.enableStompBrokerRelay("/topic", "/queue")
.setRelayHost("relayhost.mydomain.com")
.setRelayPort(61613);
@Override
public void configureClientInboundChannel(ChannelRegistration registration)
registration.setInterceptors(new MySubscriptionInterceptor());
WebSocketSecurityConfig.java:
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages)
messages
.simpSubscribeDestMatchers("/stomp/**").authenticated()
.simpSubscribeDestMatchers("/user/queue/errors").authenticated()
.anyMessage().denyAll();
MySubscriptionInterceptor.java:
public class MySubscriptionInterceptor extends ChannelInterceptorAdapter
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel)
StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
Principal principal = headerAccessor.getUser();
if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand()))
checkPermissions(principal);
return message;
private void checkPermissions(Principal principal)
// apply permissions logic
// throw Exception permissions not sufficient
当没有足够权限的客户端尝试订阅受限主题时,他们实际上从未收到来自该主题的任何消息,但也不会收到有关引发拒绝其订阅的异常的通知。相反,客户端会收到 ActiveMQ 代理一无所知的死订阅。 (正常的、获得充分许可的客户端与 STOMP 端点和主题的交互按预期工作。)
我尝试在成功连接后使用我的 Java 测试客户端订阅 users/subscribingUsername/queue/errors
和简单的 users/queue/errors
,但到目前为止,我无法从服务器收到有关订阅异常的错误消息传递到客户端。这显然不太理想,因为从来没有通知客户他们已被拒绝访问。
【问题讨论】:
【参考方案1】:您不能只在clientInboundChannel
上从MySubscriptionInterceptor
抛出异常,因为最后一个是ExecutorSubscribableChannel
,因此是async
,并且来自这些线程的任何异常最终都会以任何重新- 扔给调用者 - StompSubProtocolHandler.handleMessageFromClient
.
但是你可以做的是像clientOutboundChannel
这样的东西并像这样使用它:
StompHeaderAccessor headerAccessor = StompHeaderAccessor.create(StompCommand.ERROR);
headerAccessor.setMessage(error.getMessage());
clientOutboundChannel.send(MessageBuilder.createMessage(new byte[0], headerAccessor.getMessageHeaders()));
另一个需要考虑的选项是注解映射:
@SubscribeMapping("/foo")
public void handleWithError()
throw new IllegalArgumentException("Bad input");
@MessageExceptionHandler
@SendToUser("/queue/error")
public String handleException(IllegalArgumentException ex)
return "Got error: " + ex.getMessage();
【讨论】:
感谢@Artem,我试了一下。不幸的是,当@SubscribeMapping
方法中抛出异常并由@MessageExceptionHandler
方法处理时,一条消息被发送到客户端的错误队列,但他们的订阅仍然转发给代理,客户端仍然从主题。
所以,尝试直接使用send
到clientOutboundChannel
从那个@MessageExceptionHandler
。
@ArtemBilan 你能解释一下如何获得 OutboundChannel 吗?提出问题:***.com/questions/39641477/…以上是关于如何使用 Spring WebSocket 向 STOMP 客户端发送错误消息?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过spring websocket STOMP向特定订阅发送消息?
如何使用 spring+stomp+sockjs 获得 websocket 响应
带有 Spring-boot 后端的 Flutter websocket