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

使用Spring WebSocket开发一对一聊天应用:消息无法送达接收端

一对一聊天应用WebSocket消息无法送达接收端问题

我正在用Spring Boot和ReactJS开发一对一聊天应用,采用/queue实现一对一聊天逻辑,但遇到消息从发送方到接收方无法送达的问题。

正常功能

  • WebSocket连接正常
  • 消息可成功发送至后端

存在的问题

  • 发送给接收方的消息无法送达接收端

这是我第一次使用WebSocket,已经为此困扰3天,以下是相关代码片段:

WebSocketConfiguration

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfigure implements WebSocketMessageBrokerConfigurer {

@Override
public void registerStompEndpoints(StompEndpointRegistry registery) {
    registery.addEndpoint("/ws")
            .setAllowedOrigins("http://localhost:5173")
            .addInterceptors(new WebSocketInterceptor())
            .withSockJS();
}

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

WebSocketInterceptor

public class WebSocketInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        // Extract email from request (Assume it's passed as a query param)
        // Extract email from query params instead of headers
        URI uri = request.getURI();
        String query = uri.getQuery(); // Get query string (e.g., "user-email=aditya@gmail.com")

    if (query != null && query.contains("user-email=")) {
        String email = query.split("user-email=")[1]; // Extract email
        System.out.println("✅ User Connected: " + email);
        attributes.put("user-email", email); // Store email in session attributes
    } else {
        System.out.println("❌ No email found in query params");
    }

    return true;
}

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

}}

Chat Controller

@Controller
public class ChatController {

private final SimpMessagingTemplate simpMessagingTemplate;
private final ChatMessageService chatMessageService;


public ChatController(SimpMessagingTemplate simpMessagingTemplate, ChatMessageService chatMessageService) {
    this.simpMessagingTemplate = simpMessagingTemplate;
    this.chatMessageService = chatMessageService;
}

/**
 * Receives a message from a user, stores it in the database,
 * and sends it in real-time to the recipient only if they have that chat open.
 */
@MessageMapping("/chat")
public void sendMessage(@Payload MessageDTO messageDTO, SimpMessageHeaderAccessor headerAccessor) {

    System.out.println(messageDTO.toString());
    String receiver = messageDTO.getReceiverEmail();
    System.out.println(" Receiver is : " + receiver);

    String senderEmail = (String) headerAccessor.getSessionAttributes().get("user-email");

    if (senderEmail == null) {
        System.out.println("❌ Error: Sender email not found in session!");
        return;
    }

    MessageModel messageModel = chatMessageService.saveMessage(messageDTO);
    simpMessagingTemplate.convertAndSendToUser(receiver, "/queue/messages", messageModel);

}

/**
 * Retrieves chat history between two users when a user opens a chat room.
 */
@GetMapping("/chat/history/{user1}/{user2}")
@ResponseBody
public ResponseEntity<ApiResponse> getChatHistory(@PathVariable String user1, @PathVariable String user2) {
    return chatMessageService.getChatHistory(user1, user2);
}}

前端代码

useEffect(() => {
   
    if (!currentUserEmail || !currentUserName || !currentUserPhone || !currentUserId) {
        navigate("/");
    }

    // ================== Websocket ==================
    const socket = new SockJS(`http://localhost:8080/ws?user-email=${encodeURIComponent(currentUserEmail)}`);
    const stompClient = new Client({
        webSocketFactory: () => socket,
        // debug: (str) => {
        //     console.log(str);
        // },
        reconnectDelay: 5000,
        // heartbeatIncoming: 4000,
        // heartbeatOutgoing: 4000,
        onConnect: () => {
            console.log("Connected to WebSocket");
            // Subscribe to the user-specific queue for receiving messages
            stompClient.subscribe("/user/queue/messages", (message) => {
                const receivedMessage = JSON.parse(message.body);
                console.log("Message received: ", receivedMessage);
            });
        },
    });
    // Connect WebSocket
    stompClient.activate();
    setStompClient(stompClient);
    // ================== Websocket ==================

    fetchAllUsers();
}, [])

const sendMessage = (message, toUser) => {

    if (stompClient && stompClient.connected) {
        const msgObject = {
            senderEmail: currentUserEmail,
            receiverEmail: toUser.email,
            content: message,
            timestamp: new Date(),
        };

        stompClient.publish({
            destination: "/app/chat",
            body: JSON.stringify(msgObject),
        });

        setMessages([...messages, msgObject]);
        console.log("Message sent:", msgObject);
    } else {
        console.error("STOMP client is not connected.");
    }    };

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 06:04:51