如何拦截SimpMessagingTemplate发送的Spring WebSocket消息?
你之前的拦截器只注册到了客户端的入站/出站通道,但SimpMessagingTemplate主动发送的消息走的是服务端到消息中间件的Broker通道,和客户端交互的通道不是一回事。下面给你具体的解决步骤:
核心原因
clientInboundChannel和clientOutboundChannel负责拦截客户端与服务端之间的Stomp帧(比如订阅、发送消息请求),而SimpMessagingTemplate调用convertAndSend/convertAndSendToUser时,消息是从服务端内部转发到消息中间件(ActiveMQ)的,这条路径对应的是brokerChannel,你的拦截器没注册到这个通道上,所以抓不到这类消息。
具体解决方案
1. 升级自定义拦截器(可选但推荐)
Spring 5+之后ChannelInterceptorAdapter已经过时,建议直接实现ChannelInterceptor接口,按需重写方法:
@Component public class CustomMessageInterceptor implements ChannelInterceptor { @Override public Message<?> preSend(Message<?> message, MessageChannel channel) { // 解析消息头,区分消息类型和目标地址 SimpMessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, SimpMessageHeaderAccessor.class); if (accessor != null) { System.out.println("拦截到消息:类型=" + accessor.getMessageType()); System.out.println("目标地址=" + accessor.getDestination()); // 这里可以修改消息内容或头信息,返回修改后的消息即可 } return ChannelInterceptor.super.preSend(message, channel); } // 按需重写其他方法:postSend、afterSendCompletion等 }
2. 将拦截器注册到Broker通道
在你的WebSocket配置类(实现WebSocketMessageBrokerConfigurer)中,新增configureBrokerChannel方法,把拦截器注册到Broker通道:
@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Autowired private CustomMessageInterceptor customMessageInterceptor; // 你的原有配置:配置消息中间件、端点等 @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableStompBrokerRelay("/topic", "/queue") .setRelayHost("localhost") .setRelayPort(61613) .setClientLogin("admin") .setClientPasscode("admin"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/ws").withSockJS(); } // 你已有的客户端通道拦截器配置 @Override public void configureClientInboundChannel(ChannelRegistration registration) { registration.interceptors(customMessageInterceptor); } @Override public void configureClientOutboundChannel(ChannelRegistration registration) { registration.interceptors(customMessageInterceptor); } // 关键新增:注册拦截器到Broker通道 @Override public void configureBrokerChannel(ChannelRegistration registration) { registration.interceptors(customMessageInterceptor); } }
3. 处理用户专属消息(convertAndSendToUser)
如果是发送给特定用户的消息(convertAndSendToUser),这类消息会先经过UserDestinationMessageHandler转换目标地址,最终还是会进入brokerChannel,所以上面的配置已经能拦截到这类消息。如果需要在地址转换前后做特殊处理,可以额外给UserDestinationMessageHandler添加拦截器,但大多数场景下,拦截brokerChannel就足够了。
验证方法
启动服务后,调用SimpMessagingTemplate发送消息,查看拦截器的日志输出,就能看到服务端主动发送的消息被捕获到了。
内容的提问来源于stack exchange,提问作者Manuel Jordan

