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

STOMP WebSocket消息发送正常但前端无法接收问题求助

STOMP WebSocket前端收不到消息排查方案

我搭建了简易的STOMP WebSocket服务,后端能正常接收并处理消息,但前端订阅后收不到任何消息,前后端无报错日志。已尝试更换浏览器、用IP替代localhost,问题依旧。相关代码如下:

WebSocket配置类

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/topic");
        registry.setApplicationDestinationPrefixes("/app");
        registry.setUserDestinationPrefix("/user");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOriginPatterns("*")
                .withSockJS()
                .setInterceptors(new HttpSessionHandshakeInterceptor());
    }

    @Override
    public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
        DefaultContentTypeResolver resolver = new DefaultContentTypeResolver();
        resolver.setDefaultMimeType(MimeTypeUtils.APPLICATION_JSON);
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        converter.setObjectMapper(new ObjectMapper());
        converter.setContentTypeResolver(resolver);
        messageConverters.add(converter);
        return false;
    }
}

消息实体类

@RequiredArgsConstructor
@Getter
@AllArgsConstructor
public class ChatMessageForm {
    private  String id;
    //private  LocalDateTime timeStamp;
    private  String content;
    private  String recipientId;
    private  String senderId;
}

控制器

@Controller
@RequiredArgsConstructor
public class ChatController {

    private final ChatService chatService;

    @MessageMapping("/chat")
    public void handleChatMessage(@Payload ChatMessageForm message, SimpMessageHeaderAccessor headerAccessor) {
        chatService.handleChatMessage(new ChatMessage(
                LocalDateTime.now(),
                message.getContent(),
                message.getRecipientId(),
                message.getSenderId()
        ));
    }
}

服务实现类

@Service
@RequiredArgsConstructor
public class ChatServiceImpl implements ChatService {

    private final SimpMessagingTemplate messagingTemplate;

    @Override
    public void handleChatMessage(ChatMessage message) {
        messagingTemplate.convertAndSendToUser(
                message.getRecipientId(),
                "queue/messages",
                new ChatNotification(
                        "",
                        message.getSenderId(),
                        message.getRecipientId(),
                        message.getContent()
                )
        );
    }
}

前端连接代码

const connectWebSocket = () => {
        if (!user?.id) {
            console.error('User ID is not defined');
            return;
        }

        client.current = new Client({
            brokerURL: 'ws://127.0.0.1:8080/ws/websocket',
            debug: function (str) {
                console.log(str);
            },
            onConnect: () => {
                console.log('WebSocket connection established');
                client.current?.subscribe(`/user/${user.id}/queue/messages`, (message) => {
                    const receivedMessage: Message = JSON.parse(message.body);
                    console.log("Received message: ", receivedMessage);
                    updateChatWithNewMessage(receivedMessage);
                });
            },
            onStompError: (frame) => {
                console.error('Broker reported error: ' + frame.headers['message']);
                console.error('Additional details: ' + frame.body);
            },
            onWebSocketClose: () => {
                console.log('WebSocket connection closed');
            }
        });
        client.current.activate();
    };

排查方向及解决步骤

1. 消息代理未监听队列前缀

你的配置中enableSimpleBroker只启用了/topic前缀,但用户私信使用的/queue前缀不在监听范围内。Spring的convertAndSendToUser会生成/user/{recipientId}/queue/messages地址,若消息代理没配置监听/queue,消息无法被路由到客户端。

修复: 修改configureMessageBroker方法,添加/queue到代理监听列表:

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic", "/queue");
    registry.setApplicationDestinationPrefixes("/app");
    registry.setUserDestinationPrefix("/user");
}

2. 消息序列化异常

检查ChatNotification实体是否具备正确的序列化条件:

  • 确保添加了@Getter、@Setter或@Data(Lombok注解),否则Jackson无法序列化字段;
  • 若使用自定义ObjectMapper,确认配置支持所需的字段类型(比如Java 8时间类,若存在的话)。

3. 用户会话未绑定正确ID

convertAndSendToUser默认依赖Principal关联用户与WebSocket会话,若后端无法识别用户ID对应的会话,消息会被静默丢弃。

验证: 在ChatController的handleChatMessage中打印headerAccessor.getUser(),若返回null说明会话未绑定用户。

修复(无认证场景):
在握手时手动绑定用户ID到会话:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/ws")
            .setAllowedOriginPatterns("*")
            .withSockJS()
            .setInterceptors(new HttpSessionHandshakeInterceptor(), new HandshakeInterceptor() {
                @Override
                public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
                    // 从请求参数获取用户ID,需前端连接时携带
                    String userId = ((ServletServerHttpRequest) request).getServletRequest().getParameter("userId");
                    if (userId != null) {
                        attributes.put("userId", userId);
                        // 设置Principal供框架识别用户
                        request = new ServerHttpRequestDecorator(request) {
                            @Override
                            public Principal getPrincipal() {
                                return () -> userId;
                            }
                        };
                    }
                    return true;
                }

                @Override
                public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {}
            });
}

前端连接时携带用户ID:

brokerURL: `ws://127.0.0.1:8080/ws/websocket?userId=${user.id}`,

4. 订阅地址与发送地址不匹配

确认前端user.id与后端message.getRecipientId()的格式完全一致(大小写、空格、特殊字符等)。可在前端订阅时打印地址,后端发送时打印目标地址,对比是否完全匹配。

5. SockJS连接方式问题

若浏览器WebSocket支持存在兼容性问题,改用SockJS原生连接方式:

// 需先引入SockJS库:<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
client.current = new Client({
    webSocketFactory: () => new SockJS('http://127.0.0.1:8080/ws'),
    debug: function (str) { console.log(str); },
    onConnect: () => {
        console.log('WebSocket connection established');
        client.current?.subscribe(`/user/${user.id}/queue/messages`, (message) => {
            const receivedMessage: Message = JSON.parse(message.body);
            console.log("Received message: ", receivedMessage);
            updateChatWithNewMessage(receivedMessage);
        });
    },
    // 其他错误处理配置不变
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:14:55