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

Spring Boot WebSocket @MessageMapping端点无响应问题求助

问题:Spring Boot WebSocket @MessageMapping端点无响应

我正在学习Spring Boot WebSocket技术,按教程实现后做了自定义调整。目前React Native应用已成功建立WebSocket连接,但向@MessageMapping端点发送消息时无任何响应,使用Postman测试也未生效。

WebSocketConfig代码

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

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

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

WebSocketController代码

@Controller
public class WebSocketController {

    private final SimpMessagingTemplate messagingTemplate;
    private final Map<String, WebSocketSession> userSessions;
    private final MiqaatService miqaatService;

    public WebSocketController(SimpMessagingTemplate messagingTemplate, MiqaatService miqaatService) {
        this.messagingTemplate = messagingTemplate;
        this.miqaatService = miqaatService;
        this.userSessions = new ConcurrentHashMap<>();
    }

    @MessageMapping("/miqaat")
    public void getMiqaats(Principal principal, WebSocketSession session) {

        String userId = principal.getName();
        List<MiqaatDto> miqaats = miqaatService.getAllMiqaatByUserArea(userId);

        userSessions.put(userId, session);

        messagingTemplate.convertAndSendToUser(userId, "/queue/miqaats", miqaats);
    }

    @EventListener
    public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
        String userId = Objects.requireNonNull(event.getUser()).getName();
        userSessions.remove(userId);
    }

    public void sendUpdatedRecords(List<MiqaatDto> updatedRecords, List<User> userIds) {
        userIds.forEach(user -> {
            WebSocketSession session = userSessions.get(user.getId().toString());
            if (session != null && session.isOpen()) {
                messagingTemplate.convertAndSendToUser(user.getId().toString(), "/queue/miqaats", updatedRecords);
            }
        });
    }
}

React Native代码

const [socket, setSocket] = useState(null);

  useEffect(() => {
    const token = user.authToken;
    const headers = {
      Authorization: `${token}`,
    };

    const ws = new WebSocket("ws://192.168.0.100:8080/ws", "", { headers });

    ws.onopen = () => {
      console.log("WebSocket connection opened");

      const message = {
        destination: '/app/miqaat',
        headers: {
          // Add any additional headers if required
        },
        payload: '',
      };
    ws.send(JSON.stringify(message));
    };

    ws.onmessage = (event) => {
      const receivedData = event.data;
      const receivedRecords = JSON.parse(receivedData);
      setRecords(receivedRecords);
      console.log("records", records);
    };

    ws.onerror = (error) => {
      console.error("WebSocket error:", error);
    };

    setSocket(ws);
    return () => ws.close()
  }, []);

问题排查与解决方案

1. 协议不匹配:原生WebSocket无法识别STOMP消息格式

后端通过@EnableWebSocketMessageBroker启用了STOMP协议,但前端用原生WebSocket对象发送JSON消息,STOMP有专属帧格式,后端无法解析这种JSON结构。

解决: 前端使用STOMP客户端库(如@stomp/stompjs),兼容React Native。修改React Native代码:

import { Client } from '@stomp/stompjs';

const [stompClient, setStompClient] = useState(null);

useEffect(() => {
  const token = user.authToken;
  const client = new Client({
    brokerURL: 'ws://192.168.0.100:8080/ws',
    connectHeaders: {
      Authorization: `${token}`,
    },
    onConnect: () => {
      console.log('STOMP连接成功');
      // 订阅用户专属队列
      client.subscribe(`/user/queue/miqaats`, (message) => {
        const receivedRecords = JSON.parse(message.body);
        setRecords(receivedRecords);
        console.log("records", receivedRecords);
      });
      // 发送消息到STOMP端点
      client.publish({
        destination: '/app/miqaat',
        body: '' // 按需传递payload
      });
    },
    onWebSocketError: (error) => {
      console.error('WebSocket连接错误:', error);
    },
    onStompError: (frame) => {
      console.error('STOMP协议错误:', frame.headers['message']);
    }
  });

  client.activate();
  setStompClient(client);

  return () => {
    if (stompClient) {
      stompClient.deactivate();
    }
  };
}, []);

2. Controller方法参数注入错误

@MessageMapping方法中的WebSocketSession参数无法直接注入,STOMP协议下需用SimpMessageHeaderAccessor获取会话信息:

修改Controller方法:

@MessageMapping("/miqaat")
public void getMiqaats(Principal principal, SimpMessageHeaderAccessor headerAccessor) {
    String userId = principal.getName();
    List<MiqaatDto> miqaats = miqaatService.getAllMiqaatByUserArea(userId);
    
    // 获取会话ID(如果需要)
    String sessionId = headerAccessor.getSessionId();
    // 无需手动存储WebSocketSession,SimpMessagingTemplate已处理会话关联
    
    messagingTemplate.convertAndSendToUser(userId, "/queue/miqaats", miqaats);
}

3. Postman测试方式错误

Postman测试STOMP需遵循STOMP帧格式,步骤:

  1. 建立WebSocket连接到ws://192.168.0.100:8080/ws
  2. 发送CONNECT帧(末尾需空行+NULL字符,Postman用Ctrl+Shift+P插入NULL):
    CONNECT
    Authorization: YOUR_TOKEN
    accept-version:1.2,1.1,1.0
    heart-beat:10000,10000
    
    ^@
    
  3. 连接成功后发送SEND帧:
    SEND
    destination:/app/miqaat
    
    ^@
    

4. 权限验证问题

确保Principal principal能正确获取用户ID:

  • 检查Token解析逻辑,确认Spring Security认证成功后已填充Principal
  • 在Controller方法中打印principal.getName(),验证是否获取到有效用户ID

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:14:51