我正在尝试使用RabbitMQ作为外部代理在Spring 4中配置Web套接字支持,但是当我切换到RabbitMQ时,我在客户端启动时收到以下错误:
'/user/queue/changes' is not a valid destination.
Valid destination types are: /temp-queue, /exchange, /topic, /queue, /amq/queue, /reply-queue/.
在我使用convertAndSendToUser
的服务器上,这对于简单的代理可以正常工作,但是一旦切换到RabbitMQ,我就会收到此错误。请注意,RabbitMQ适用于普通主题广播 - 它只是/user
频道失效。
我是否需要做一些特别的事情才能让/user
与RabbitMQ一起使用?
编辑以包含Web套接字配置
我的WebSocketConfig
非常标准,有一些自定义功能可以将其与spring-session集成:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractSessionWebSocketMessageBrokerConfigurer<ExpiringSession> {
@Override
public void configureStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/changes").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
//config.enableSimpleBroker("/queue", "/topic");
StompBrokerRelayRegistration r = config.enableStompBrokerRelay("/user", "/topic");
try {
String rabbitUrl = System.getenv("CLOUDAMQP_URL");
if(rabbitUrl != null) {
log.info("RABBIT URL detected: " + rabbitUrl);
URI uri = new URI(rabbitUrl);
String host = uri.getHost();
String login = uri.getUserInfo().split(":",2)[0];
String passCode = uri.getUserInfo().split(":",2)[1];
String vhost = uri.getPath().substring(1);
r.setRelayHost(host);
r.setSystemLogin(login);
r.setSystemPasscode(passCode);
r.setClientLogin(login);
r.setClientPasscode(passCode);
r.setVirtualHost(vhost);
}
} catch(Exception e) {
log.error("Error setting up RabbitMQ", e);
}
config.setApplicationDestinationPrefixes("/app");
}
}
答案 0 :(得分:2)
这是一个很老的问题,但是我遇到了同样的错误,因此我的解决方案可能适用于其他人。这基本上是@Memo 313 MediaSA所说的(以及他的回答被否决的原因)。 我发现的两个关键点是:
完成这些操作后,一切都应按setUserDestinationPrefix方法的文档说的那样工作:
例如,当用户尝试订阅“ / user / queue / position-updates”时, 目的地可以翻译为“ / queue / position-updatesi9oqdfzo”,从而产生一个 不与尝试执行此操作的任何其他用户冲突的唯一队列名称。 随后,当邮件发送到“ / user / {用户名} / queue / position-updates”时, 目的地将转换为“ / queue / position-updatesi9oqdfzo”。
此外,请确保您的应用程序使用的{username}与principal相同。
答案 1 :(得分:1)
我遇到了类似的错误,但在搜索互联网后我找不到直观的解决方案。
我想在完成RabbitMQ STOMP的文件后分享我的发现。
根据RabbitMQ STOMP的文档,只允许以/exchange
,/queue
,/amq/queue
,/topic
和temp-queue
开头的目的地。目的地/user/*
将不被允许。您可以根据邮件要求选择目的地。
/ exchange - 发送到任意路由密钥和SUBSCRIBE到任意 绑定模式;
/ queue - SEND和SUBSCRIBE到STOMP网关管理的队列;
/ amq / queue - 对在STOMP外部创建的队列进行SEND和SUBSCRIBE 网关;
/ topic - 发送和订阅瞬态和持久主题;
/ temp-queue / - 创建临时队列(仅在回复标题中)。
例如,我想向主题发送消息以通知所有订阅者。
对于提供每封邮件副本的简单主题目标 所有活跃订阅者, / topic /&lt;形式的目的地名称&gt; 可以 用过的。主题目标支持AMQP的所有路由模式 主题交流。
发送到没有活动订阅者的主题目标的邮件 被丢弃了。
AMQP 0-9-1语义
对于SEND帧,邮件将发送到 amq.topic 交换 路由密钥&lt;名称&gt;。
对于SUBSCRIBE帧,将创建一个自动删除的非持久队列 绑定到 amq.topic 交换路由密钥&lt;名称&gt;。一个 订阅是根据队列创建的。
规范意味着目标为/topic/<name>
的stomp子消息将使用rabbitmq的默认交换 amp.topic ,然后可以使用变量名称<创建绑定/ strong>如果它不存在并且还创建了一个队列以通过该绑定绑定交换 amp.topic 。
如果要创建持久订阅,客户端应发送带有以下标题的订阅消息。
durable:true
auto-delete:false
在我的应用中,websocket服务器收到消息/watch/{liveid}
,然后向主题/topic/watchinfo-{liveid}
回复另一条消息。
@Secured(User.ROLE_USER)
@MessageMapping("/watch/{liveid}")
@SendTo("/topic/watchinfo-{liveid}")
@JsonView(View.Live.class)
public LiveWatchInfoMessage liveinfo(@DestinationVariable("liveid") String liveid,
@AuthenticationPrincipal UserDetails activeUser) {
...
return LiveWatchInfoMessage.builder().build();
}
答案 2 :(得分:-1)
我在订阅js方法的开头删除了/,错误不再存在。 旧子:stompClient.subscribe(“ / user / queue / specific-user-user”,....给出错误,新子:stompClient.subscribe(“ user / queue / specific-user-user”没有错误>
答案 3 :(得分:-2)
我猜问题就在于此 StompBrokerRelayRegistration r = config.enableStompBrokerRelay(&#34; / user&#34;,&#34; / topic&#34;) 但是你要指定&#34; / queue / loop-changes&#34;在convertAndSendToUser.change StompBrokerRelayRegistration中(&#34; / queue&#34;,&#34; / topic&#34;)。 我有一个后续问题,Spring会将sessionid附加到redditmq的目标。这个sessionid从DefaultUserSessionRegistry获取 - &gt; userSessionIds。它会在集群中工作吗?