@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-chat")
.setAllowedOriginPatterns("*") // 이거 있어야 외부에서도 접근 가능
.withSockJS();
}
- /ws-chat가 맞아.
- 근데 .withSockJS()를 썼네?
➡️ withSockJS()를 쓰면 클라이언트도 SockJS 프로토콜로 연결해야 해.
즉, 그냥 WebSocket으로는 안 된다.
SockJS는 표준 WebSocket과 handshake 방식이 달라서 Postman이 못 붙는다.
현재 설정상
withSockJS() 붙음 | 표준 WebSocket 클라이언트 (Postman) 못 붙음 |
일반 WebSocket 연결 | 실패 |
SockJS 클라이언트 필요 | 맞음 |
- Postman은 SockJS 지원 못 해.
- JavaScript 코드 또는 Hoppscotch 같은 곳에서 SockJS를 지원하는 코드 짜야 돼.
- 이건 테스트 귀찮아져서 일반 WebSocket으로 바꾸는 걸 추천해.
- Postman으로 WebSocket 테스트하려면 withSockJS()를 빼야 한다.
- registry.addEndpoint("/ws-chat").setAllowedOriginPatterns("*");로 수정하고 서버 재시작
- 그다음 Postman에서 ws://localhost:8080/ws-chat로 연결하면 정상.
✅ Postman WebSocket → SockJS는 지원하지 않음
이 설정은 클라이언트가 SockJS 프로토콜로 연결해야 정상 작동해.
근데 Postman은 표준 WebSocket (ws://)만 지원하고, SockJS는 미지원이야.
🔍 WebSocket vs Socket.IO 차이
항목 | WebSocket | Socket.IO |
프로토콜 | 표준 WebSocket 프로토콜 (ws://, wss://) | 자체 프로토콜 (WebSocket 위에서 동작하는 라이브러리) |
표준 여부 | RFC 6455로 정의된 브라우저 표준 | 브라우저 표준 아님 (Node.js 기반에서 시작된 확장 기술) |
전송 형식 | 순수 텍스트/바이너리 | JSON 기반 자체 포맷 (handshake도 다름) |
연결 방식 | 클라이언트 ↔ 서버 간 단순한 지속 연결 | handshake → ping/pong, namespace, room, ack 등 다양한 기능 내장 |
사용 목적 | 실시간 단순 통신 (ex. 채팅, 주식시세 등) | 실시간 + 복잡한 기능 (ex. 방송 구독, 그룹 채팅, 재접속 등) |
호환성 | 어떤 언어든 WebSocket 구현만 있으면 가능 | 클라이언트/서버 둘 다 Socket.IO 라이브러리 필요 |
예시 | Spring WebSocket, ws (Node.js) | Express + socket.io, NestJS + gateway |
➡️ Socket.IO는 WebSocket보다 상위 추상화된 기능을 제공하는 자체 통신 프레임워크라고 보면 돼.
🔌 1. WebSocket 연결
먼저 WebSocket 연결은 오직 한 번 이루어져:
ws://localhost:8080/ws-chat
이건 WebSocket 핸드셰이크를 위한 URL이야.
연결되면 클라이언트와 서버는 계속 열린 상태로 메시지를 주고받을 수 있어.
📦 2. STOMP 프로토콜로 통신
Spring은 WebSocket 위에서 **STOMP (Simple Text Oriented Messaging Protocol)**를 사용해.
STOMP는 메시지를 주고받을 때 "구독"/"발행" 채널을 명확히 구분하는데,
HTTP처럼 "어떤 경로에 무엇을 보내는가"가 STOMP 프레임으로 정의돼.
💬 3. 구독(subscribe)과 전송(send) 경로는 STOMP 내부에서 사용됨
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
// private final StompHandler stompHandler;
//
// public StompWebSocketConfig(StompHandler stompHandler) {
// this.stompHandler = stompHandler;
// }
// 메세지 받기: /topic
// 메시지 전송: /app
// 메시지 브로커 설정 (/topic, /queue 등)
// WebSocket STOMP 연결 (SockJS 지원)
// WebSocket 연결: /ws-chat
// WebSocket 핸드셰이크 엔드포인트 설정
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws-chat")// 클라이언트가 연결할 endpoint
// .setAllowedOrigins("*")// CORS 허용
.setAllowedOriginPatterns("*")
// .withSockJS()
;// SockJS 지원
}
// 메시지 브로커 설정 (구독 채널: /topic)
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 메시지 구독 prefix
// 서버 → 클라이언트 메세지 전송
// prefix, 구독 경로
// /topic -> broadcast 용 (채팅방 등 다수 사용자 대상)
// /queue -> 1:1 개인 메시지용 (point-to-point)
// localhost:8080/ws-chat/topic/chat/{roomId}
registry.enableSimpleBroker("/topic", "/queue");
// 메시지 전송 prefix
// 클라이언트 → 서버 메시지 전송 prefix
// 메시지 송신 경로 prefix
registry.setApplicationDestinationPrefixes("/app", "/pub");
// convertAndSendToUser 위한 prefix
// 특정 사용자에게 보내기 위한 prefix (e.g. 1:1 알림, 귓속말)
// localhost:8080/ws-chat/user/queue/messages
registry.setUserDestinationPrefix("/user");
}
}
@Service
@RequiredArgsConstructor
public class WebSocketSender {
/**
* Spring WebSocket은 STOMP 프로토콜 위에서 작동하는데
* SimpMessageSendingOperations 구현체 내부적으로 STOMP를 알아서 처리함
*/
private final SimpMessagingTemplate messagingTemplate;
/**
* Test > StompChatController > @MessageMapping("/chat") 이 붙은 클라이언트들이 자동으로 메시지를 받음
* 세션 ID나 커넥션 직접 안 잡아도 됨 ->직접 WebSocket 세션 추적, 사용자 매핑, 메시지 전송 로직 필요 없음
*/
public void sendToChatRoom(String key, Object payload) {
messagingTemplate.convertAndSend("/topic/chat/" + key, payload);
}
/**
* Spring은 WebSocket 연결 시 user 정보까지 매핑해줄 수 있어서
* 특정 사용자한테만 보내는 것도 쉽게 가능
* 1:1 알림, 귓속말
*/
public void sendToUser(String userId, Object payload) {
messagingTemplate.convertAndSendToUser(userId, "/queue/messages", payload);
}
}
/**
* STOMP 기반 채팅 브로드캐스트 컨트롤러
* <p>
* ✅ 용도:
* - 간단한 실시간 메시지 브로드캐스팅
* - 테스트/프로토타입용
* <p>
* ❌ 한계:
* - 인증, 유저별 구독 관리 불가
* - 세션 추적 및 고급 권한 처리 불가
*/
@Slf4j
@Controller
public class StompChatController {
// 구독: JS: stompClient.subscribe("/topic/chat/{roomId}", callback)
// 메세지 전송: JS: stompClient.send("/app/chat/{roomId}", {}, JSON.stringify(message)) -> @MessageMapping("/chat/{roomId}")
// 브로드캐스팅: @SendTo("/topic/chat/{roomId}")-> 구독 중인 모든 클라이언트에게 전달
@MessageMapping("/chat/{roomId}")
//@SendTo: 프로토타입, 간단한 실시간 테스트 용도
@SendTo("/topic/chat/{roomId}")
public ChatMessageDto sendMessage(@DestinationVariable String roomId, ChatMessageDto message) {
log.info("🔔 [TEST-STOMP] message received - roomId: {}, senderId: {}, content: {}", roomId, message.getSenderId(), message.getContent());
// 메시지에 채팅방 ID 및 전송 시간 설정 (테스트용)
message.setChatRoomId(UUID.fromString(roomId));
message.setCreatedAt(LocalDateTime.now());
return message;
}
}
📡 구독 | 클라이언트가 특정 채널을 구독함 (서버 → 클라 메시지 수신용) | /topic/chat/{roomId} |
📤 메시지 전송 | 클라이언트가 서버로 메시지를 보냄 | /app/chat/{roomId} |
SEND
destination:/topic/chat/6d30530c-e5ea-4cfd-b52e-a37b1b1d2e41
content-type:application/json
https://stackoverflow.com/questions/71696431/how-to-test-stomp-application-using-postman
How to test stomp application using postman?
I am making a chat application backend using spring WebSockets. The protocol for communication is STOMP and I am using rabbitmq as a message broker. I want to test my application using postman but ...
stackoverflow.com
🔥 목표
Spring 서버:
- ws://localhost:8080/ws-chat
- STOMP 기반
- /app/chat/{roomId}로 전송
- /topic/chat/{roomId} 구독
withSockJS()는 제거되어 있어야 해!
이유: telnet, netcat은 pure WebSocket만 가능, SockJS는 handshake 방식이 달라서 못 붙음.
curl | ❌ WebSocket 불가 |
telnet / nc | ❌ WebSocket 핸드셰이크 못함 |
✅ wscat | WebSocket + STOMP 직접 전송 가능 (강력 추천) |
✅ WebSocket 연결 후 STOMP 프레임 수동 전송 (예: netcat + wscat)
하지만 기본 curl, telnet, nc는 WebSocket 핸드셰이크 자체를 못함.
그래서 필요한 도구는 wscat
npm install -g wscat
wscat -c ws://localhost:8080/ws-chat
CONNECT
accept-version:1.2
heart-beat:10000,10000
\x00
✅ 연결되면 CONNECTED 프레임이 옴.
SUBSCRIBE
id:sub-0
destination:/topic/chat/room123
\x00
SEND
destination:/app/chat/room123
content-type:application/json
{"senderId":"abc-123","content":"hello from wscat"}\x00
'학습 기록 (Learning Logs) > Today I Learned' 카테고리의 다른 글
🔎 Read Lock, ✏ Write Lock (0) | 2025.05.02 |
---|---|
Solana Breakout Hackathon (0) | 2025.04.30 |
로컬에서 채팅 테스트 (0) | 2025.04.23 |
컴퓨터 핵심 부품(메모리, cpu, 보조기억장치, 보조기억장치) (0) | 2025.04.23 |
실시간 데이터 동기화 (0) | 2025.04.17 |