You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot WebSocket STOMP无法发送私信问题排查

Spring Boot 3 WebSocket STOMP 点对点消息无法送达问题

我基于Spring Boot 3实现了一套客户端-服务端聊天应用,采用WebSocket + STOMP协议通信,服务端与客户端使用不同版本的Spring及Spring Boot。目前已实现公共topic消息发送功能,消息经过加密,仅目标客户端可解密查看,但点对点消息始终无法送达目标客户端。


消息处理控制器代码

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
@Autowired
private ActiveUserStore activeUserStore;

@MessageMapping("/send")
@SendToUser("/queue/chat")
public void sendToUser(@Payload WsIncomingMessage wsIncomingMessage, Principal user, @Header("simpSessionId") String sessionId) {
    log.info(" /queue/chat > incoming msg: {}, user: {}, header: {}", wsIncomingMessage, user, sessionId);
    WsOutgoingMessage wsOutgoingMessage = new WsOutgoingMessage();
    wsOutgoingMessage.setMessage(wsIncomingMessage.getMessage());
    wsOutgoingMessage.setMessageType(wsIncomingMessage.getMessageType());
    wsOutgoingMessage.setSentDatetime(wsIncomingMessage.getSentDatetime());
    wsOutgoingMessage.setSource(wsIncomingMessage.getSource());
    wsOutgoingMessage.setDestination(wsIncomingMessage.getDestination());
    wsIncomingMessage.setAdId(wsIncomingMessage.getAdId());
    log.info(" /queue/chat > outgoing msg: {}, user: {}, header: {}", wsIncomingMessage, user, sessionId);
    
    simpMessagingTemplate.convertAndSendToUser(activeUserStore.getUser(wsOutgoingMessage.getDestination()).getPrincipal(), "/queue/chat", wsOutgoingMessage);
}

注:activeUserStore.getUser(wsOutgoingMessage.getDestination()).getPrincipal()返回用户唯一标识手机号。

自定义握手处理器代码

@Slf4j
public class CustomHandshakeHandler extends DefaultHandshakeHandler { 
    
    @Override
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
            Map<String, Object> attributes) {
        String uuid = UUID.randomUUID().toString();
        Principal principal = request.getPrincipal();

        if (principal instanceof UsernamePasswordAuthenticationToken) {
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) principal;
            Object principalObj = usernamePasswordAuthenticationToken.getPrincipal();
            if (principalObj instanceof JwtUserDetails) {
                JwtUserDetails connectingUser = (JwtUserDetails) principalObj;
                connectingUser.setSessionUuid(uuid);
                
            }
        }
        log.info("principal in CustomHandshakeHandler: {}", principal);
        return principal;
    }
}

Principal实例信息

UsernamePasswordAuthenticationToken [Principal=JwtUserDetails(id=3, name=Anupam, principal=+855964572928, password=, sessionUuid=0c4169cd-0289-4233-a6f4-0ec04ea3d08c, authorities=[JwtGrantedAuthority(authorityName=USER)]), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[JwtGrantedAuthority(authorityName=USER)]]

服务端日志信息

消息接收日志

[boundChannel-13][0;39m [36mc.l.c.f.k.c.controller.ChatController   [0;39m [2m:[0;39m  /queue/chat > incoming msg: WsIncomingMessage(message=Hi, messageType=text/plain, destination=4, sentDatetime=2023-04-29T10:39:49+07:00, source=3, sourceImage=0, adId=no-ad), user: UsernamePasswordAuthenticationToken [Principal=JwtUserDetails(id=3, name=Anupam, principal=+855964572928, password=, sessionUuid=0c4169cd-0289-4233-a6f4-0ec04ea3d08c, authorities=[JwtGrantedAuthority(authorityName=USER)]), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[JwtGrantedAuthority(authorityName=USER)]], header: 36d934da-79d7-f00b-6459-331f1cef60ca

[boundChannel-13][0;39m [36mc.l.c.f.k.c.controller.ChatController   [0;39m [2m:[0;39m  /queue/chat > outgoing msg: WsIncomingMessage(message=Hi, messageType=text/plain, destination=4, sentDatetime=2023-04-29T10:39:49+07:00, source=3, sourceImage=0, adId=no-ad), user: UsernamePasswordAuthenticationToken [Principal=JwtUserDetails(id=3, name=Anupam, principal=+855964572928, password=, sessionUuid=0c4169cd-0289-4233-a6f4-0ec04ea3d08c, authorities=[JwtGrantedAuthority(authorityName=USER)]), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[JwtGrantedAuthority(authorityName=USER)]], header: 36d934da-79d7-f00b-6459-331f1cef60ca

订阅事件日志

event: SessionSubscribeEvent[GenericMessage [payload=byte[0], headers={simpMessageType=SUBSCRIBE, stompCommand=SUBSCRIBE, nativeHeaders={destination=[/user/queue/chat], id=[0]}, simpSessionAttributes={}, simpHeartbeat=[J@197209d9, simpSubscriptionId=0, simpUser=UsernamePasswordAuthenticationToken [Principal=JwtUserDetails(id=3, name=Anupam, principal=+855964572928, password=, sessionUuid=0c4169cd-0289-4233-a6f4-0ec04ea3d08c, authorities=[JwtGrantedAuthority(authorityName=USER)]), Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[JwtGrantedAuthority(authorityName=USER)]], simpSessionId=36d934da-79d7-f00b-6459-331f1cef60ca, simpDestination=/user/queue/chat}]]

客户端日志信息

StompSession.Subscription messageSubscriberSubscription = sessionStomp.get().subscribe("/user/queue/chat", messageSubscriber);
log.info("messageSubscriberSubscription: {}", messageSubscriberSubscription);

10:39:43.244 [Grizzly(2)] INFO com.lomatechnology.cambodia.fintech.kke.chat.web.ServerCommunication -- messageSubscriberSubscription: Subscription [id=0, destination='/user/queue/chat', receiptId='null', handler=com.lomatechnology.cambodia.fintech.kke.chat.web.MessageSubscriber@39fe1782]
10:39:49.022 [AWT-EventQueue-0] INFO com.lomatechnology.cambodia.fintech.kke.chat.util.DatetimeUtil -- Returned date string: 2023-04-29T10:39:49+07:00
10:39:49.022 [AWT-EventQueue-0] INFO com.lomatechnology.cambodia.fintech.kke.chat.ui.ChatGui -- About to send: WsOutgoingMessage(message=Hi, messageType=text/plain, destination=4, sourceImage=null, sentDatetime=2023-04-29T10:39:49+07:00, source=3, adId=no-ad)

核心疑问

目前服务端能正常接收STOMP消息,客户端订阅也显示成功,但目标客户端始终收不到消息。请问是convertAndSendToUser中Principal的使用有误,还是遗漏了其他配置?


内容的提问来源于stack exchange,提问作者Sandah Aung

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:14:56