Skip to content

连接到代理

STOMP 代理中继(Broker Relay)需要与外部消息代理建立 TCP 连接。本节介绍相关的连接配置。

系统连接 vs 客户端连接

代理中继共维护两类连接:

  1. 系统级连接: 只有一条。用于服务器端应用发送广播消息。
    • systemLoginsystemPasscode: 默认为 guest/guest
  2. 客户端连接: 代理中继会为每个已连接的 WebSocket 客户端创建一个对应的 TCP 连接。
    • clientLoginclientPasscode: 默认为 guest/guest

TIP

代理中转员会代为设置 CONNECT 帧的标头,因此WebSocket 客户端不需要在前端设置用户名和密码,它们会被忽略。建议在 HTTP 握手阶段通过 Spring Security 进行身份验证。

心跳与重连

代理中继在“系统级连接”上发送和接收心跳(默认为 10 秒)。如果连接丢失,它会每隔 5 秒尝试重新连接,直到成功为止。

配置多地址 (多机高可用)

你可以配置一个地址供应器,而不是固定的单机地址:

java
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableStompBrokerRelay("/queue/", "/topic/")
            .setTcpClient(createTcpClient());
}

private ReactorNettyTcpClient<byte[]> createTcpClient() {
    return new ReactorNettyTcpClient<>(
            client -> client.remoteAddress(() -> new InetSocketAddress(0)), // 此处可配置负载均衡逻辑
            new StompReactorNettyCodec());
}
kotlin
override fun configureMessageBroker(registry: MessageBrokerRegistry) {
    registry.enableStompBrokerRelay("/queue/", "/topic/")
            .setTcpClient(createTcpClient())
}

private fun createTcpClient(): ReactorNettyTcpClient<ByteArray> {
    return ReactorNettyTcpClient({ it.addressSupplier { InetSocketAddress(0) } }, StompReactorNettyCodec())
}

补充教学

1. 为什么有两套账号?

  • 客户端账号: 权限通常受到限制,只能订阅和发送特定目的地。
  • 系统账号: 往往拥有管理员权限,可以给任何目的地发通知。 在 RabbitMQ 中,你通常会为应用专门创建一个名为 stomp_user 的账号并分配 VHost 权限。

2. 用户身份识别

由于代理中继会为每个 WebSocket 客户端“开后门”去连接 MQ,如果你需要 MQ 的插件也能看到具体用户信息,可以考虑实现 StompHeaderAccessor 的动态登录逻辑,但在绝大多数场景下,使用默认的 guest 账号并通过应用层做拦截已经足够。

3. 可用性监听

你可以实现 ApplicationListener<BrokerAvailabilityEvent>。当 MQ 挂掉时,你的系统连接会断开,此时你可以通过这个事件关掉一些不必要的推送逻辑,避免连接池积压。

Based on Spring Framework.