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帧格式,步骤:
- 建立WebSocket连接到
ws://192.168.0.100:8080/ws - 发送CONNECT帧(末尾需空行+NULL字符,Postman用Ctrl+Shift+P插入NULL):
CONNECT Authorization: YOUR_TOKEN accept-version:1.2,1.1,1.0 heart-beat:10000,10000 ^@ - 连接成功后发送SEND帧:
SEND destination:/app/miqaat ^@
4. 权限验证问题
确保Principal principal能正确获取用户ID:
- 检查Token解析逻辑,确认Spring Security认证成功后已填充Principal
- 在Controller方法中打印
principal.getName(),验证是否获取到有效用户ID
内容的提问来源于stack exchange,提问作者Moiz Chittalwala
相关产品推荐
相关产品推荐

