
HTTP는 기본적으로 상태를 기억하지 않는 Stateless 프로토콜이다. 로그인 유지나 사용자 컨텍스트는 세션/쿠키 같은 별도 메커니즘이 필요하다. 실시간성은 HTTP 단독으로 한계가 있어, Polling·Long-Polling·SSE·WebSocket·STOMP 등의 기술을 상황에 맞게 조합한다.
DeferredResult)핵심 콜백(스프링 DeferredResult)
setResult(T), setErrorResult(Object)onCompletion(Runnable), onTimeout(Runnable), onError(Consumer<Throwable>)간단 예시:
@GetMapping("/long-poll")
public DeferredResult<String> longPoll() {
DeferredResult<String> output = new DeferredResult<>(30_000L); // 30s timeout
// 비동기 이벤트가 오면 setResult 호출
someAsyncEventBus.register(result -> output.setResult(result));
output.onTimeout(() -> output.setErrorResult("timeout"));
return output;
}
SseEmitter)핵심 메소드(SseEmitter)
send(Object), complete(), completeWithError(Throwable)onTimeout(Runnable), onCompletion(Runnable)간단 예시:
@GetMapping(value="/sse", produces="text/event-stream")
public SseEmitter sse() throws IOException {
SseEmitter emitter = new SseEmitter(0L); // no timeout
emitter.send(SseEmitter.event().name("init").data("connected"));
// 이후 다른 스레드/이벤트에서 emitter.send(...) 반복
return emitter;
}
WebSocketHandlerRegistry, WebSocketSession)핵심 설정
addHandler(WebSocketHandler, paths...)setAllowedOrigins(...), addInterceptors(...), withSockJS()예시(핸들러 등록):
@Configuration
@EnableWebSocket
public class WsConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry r) {
r.addHandler(new ChatHandler(), "/ws-chat")
.setAllowedOrigins("*")
.withSockJS();
}
}
세션 사용:
class ChatHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage msg) throws Exception {
if (session.isOpen()) session.sendMessage(new TextMessage("echo: " + msg.getPayload()));
}
}
핵심 설정(WebSocketMessageBrokerConfigurer)
registerStompEndpoints(...) 엔드포인트 등록configureMessageBroker(...) 브로커/프리픽스 설정enableSimpleBroker("/topic"), setApplicationDestinationPrefixes("/app")예시(설정 + 메시지 전송):
@Configuration
@EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
@Controller
@RequiredArgsConstructor
class ChatController {
private final SimpMessagingTemplate template;
@MessageMapping("/chat/{roomId}")
public void send(@DestinationVariable String roomId, ChatMessage msg) {
template.convertAndSend("/topic/chat/" + roomId, msg);
}
}
테스트 도구: https://jiangxy.github.io/websocket-debug-tool/
| 기술 | 방식 | 장단점 | 적합한 상황 |
|---|---|---|---|
| Polling | 주기적 요청 | 구현 단순·부하↑·실시간성↓ | 간단한 갱신 확인 |
| Long-Polling | 응답 지연 후 즉시 반환 | 불필요 요청↓·자원관리 필요 | 간헐 알림/변경 즉시 반영 |
| SSE | 서버→클라이언트 푸시(단방향) | 가볍고 쉬움·단방향 | 알림/피드/이벤트 스트림 |
| WebSocket | 양방향 지속 연결 | 강력한 실시간·관리 필요 | 채팅/게임/주가/보드 |
| STOMP | WebSocket 위 pub/sub | 구조화·확장성↑·학습 필요 | 다중 룸/브로커 연동/권한 |