[์ผ] ํ๋ฉด์ด ์ค์๊ฐ์ผ๋ก ๋ฐ๋์ด์ผ ํ๋ ์๊ตฌ์ฌํญ์ ํด๊ฒฐํด๋ณด์ (1) ๋ฐฑ์๋ : WebSocket ๊ตฌํ
ํด๋ผ์ด์ธํธ์ ํ๋ฉด์ด ์ค์๊ฐ์ผ๋ก ๋ฐ๋๋ ์๊ตฌ์ฌํญ
๋ค์ํ ๋ฐฉ์ ๋น๊ต
WebSocket ์ ํํจ
WebSocket
์๋ฒ์์ ์ฐ๊ฒฐ์ ํตํด ์๋ฐฉํฅ ํต์ ์ด ๊ฐ๋ฅํ๋ค.
HTTP Polling
ํด๋ผ์ด์ธํธ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ์๋ฒ์๊ฒ ์์ฒญ์ ๋ณด๋ด๋ ๋ฐฉ์์ด๋ค.
Server-Sent Events(SSE)
์๋ฒ์ ํ ๋ฒ ์ฐ๊ฒฐ์ ๋งบ๊ณ ๋๋ฉด ์ผ์ ์๊ฐ ๋์ ์๋ฒ์์ ๋ณ๊ฒฝ์ด ๋ฐ์ํ ๋๋ง๋ค ๋ฐ์ดํฐ๋ฅผ ์ ์ก๋ฐ๋ ๋ฐฉ๋ฒ์ด๋ค. ๋จ๋ฐฉํฅ ํต์ ์ด๋ค.
| WebSocket | SSE | HTTP Polling | |
| ํต์ ๋ฐฉํฅ | ์๋ฐฉํฅ | ๋จ๋ฐฉํฅ (์๋ฒ → ํด) | ๋จ๋ฐฉํฅ (์๋ฒ → ํด) |
| ์ฐ๊ฒฐ ์ ์ง ๋ฐฉ์ | ์ง์ ์ฐ๊ฒฐ | ์ง์ ์ฐ๊ฒฐ | ์ฐ๊ฒฐ-์๋ต-์ฌ์ฐ๊ฒฐ ๋ฐ๋ณต |
| ๋ธ๋ผ์ฐ์ ์ง์ | ๊ฑฐ์ ๋ชจ๋ | ์ผ๋ถ IE ๋ฏธ์ง์ | ๊ฑฐ์ ๋ชจ๋ |
| ์๋ฒ ๋ถํ | ๋ฎ์ | ๋ฎ์ | ๋์ |
| ์ง์ฐ ์๊ฐ | ๋งค์ฐ ๋ฎ์ | ๋ฎ์ | ์ค๊ฐ~๋์ |
| ๊ตฌํ ๋ณต์ก๋ | ์ค๊ฐ | ์ฌ์ | ์ฌ์ |
์๋ ๋ก์ง

1. ๋ก๊ทธ์ธ ์๋ฃ ํ ์์ ํ์ด์ง
- ๋ก๊ทธ์ธ๊ณผ ๋์์ ์ํ ๋ฆฌํด
2. ์ ์ ์ ๋ณด๋ฑ๋ก ํ์ด์ง
- ์ฌ์ฉ์๊ฐ ์ ์ ์ ๋ณด ๋ฑ๋ก์ ์๋ฃํ๋ฉด
์๋ฒ์์ ๊ฒฐ๊ณผ์ ๋ฐ๋ผ ๊ตฌ๋
ํ๊ณ ์๋ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ฆฐ๋ค
3. ๋ถ๋ถ์ฝ๋ํ์ธ ํ์ด์ง
- ์ฌ์ฉ์๊ฐ ๋ถ๋ถ ์ฐ๊ฒฐ์ ์๋ฃํ๋ฉด {์ ์ผํ ์์ ID๊ฐ : ์ ์ ์์ด๋ 2๊ฐ ์ ๋ณด}๊ฐ ๋ ๋์ค์ ์ ์ฅ๋๋ค.
- ์ด๋ ํ ์ฌ์ฉ์๊ฐ ์ฝ๋๋ฅผ ์ธ์ฆํ๋ฉด
๋ฐฐ์ฐ์๋ ํ๋ฉด์ด ์๋์ผ๋ก ์ ํํ๊ธฐ ์ํด ๊ตฌ๋
ํ๊ณ ์๋ ์ฌ๋๋ค์๊ฒ ์ํ ๋ณํ๋ฅผ ์๋ฆฐ๋ค.
4. ๋ถ๋ถ์ ๋ณด๋ฑ๋ก ํ์ด์ง
- ์ฌ์ฉ์๊ฐ ๋ถ๋ถ ์ ๋ณด ๋ฑ๋ก ๋๋ฅด๋ฉด
์ด๋ ํ ์ฌ์ฉ์๊ฐ ์ฝ๋๋ฅผ ์ธ์ฆํ๋ฉด
๋ฐฐ์ฐ์๋ ํ๋ฉด์ด ์๋์ผ๋ก ์ ํํ๊ธฐ ์ํด ๊ตฌ๋
ํ๊ณ ์๋ ์ฌ๋๋ค์๊ฒ ์ํ ๋ณํ๋ฅผ ์๋ฆฐ๋ค.
5. ํ ํ์ด์ง
WebSocket ํ๋กํ ์ฝ
1. ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ WebSocket ์ฐ๊ฒฐ์ ์์ฒญํ๋ ๋จ๊ณ
2. ์ฐ๊ฒฐ์ด ์ค์ ๋ ํ์ ์ค์ ๋ฐ์ดํฐ๊ฐ ๊ตํ๋๋ ๋จ๊ณ
HTTP ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์๋์ง๋ง, ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ WebSocket ์ฐ๊ฒฐ๋ก ์ ๊ทธ๋ ์ด๋ํ๋ ค๋ ์๋๋ฅผ ๋ช ํํ ํด์ผ ํ๋ค.
- ํด๋ผ์ด์ธํธ ์ธก : ์ฐ๊ฒฐ ์์ฒญ ํค๋
- ์๋ฒ : ํด๋ผ์ด์ธํธ ์์ฒญ์ ๋ฐ์๋ค์ด๊ณ , 101 Switching Protocols ์ํ ์ฝ๋๋ก ์๋ตํ์ฌ ์ฐ๊ฒฐ์ WebSocket ํ๋กํ ์ฝ๋ก ์ ๊ทธ๋ ์ด๋
- ํ ์คํธ ๋ฐ์ดํฐ : UTF-8 ์ธ์ฝ๋ฉ ๋ฌธ์์ด
- ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ : ์ด๋ฏธ์ง & ๋น๋์ค ์คํธ๋ฆผ
- ํด๋ผ์ด์ธํธ ๋๋ ์๋ฒ ์ธก: ์ข ๋ฃ ์์ฒญ (Close Request)
ํด๋ผ์ด์ธํธ ๋๋ ์๋ฒ๊ฐ close ๋ฉ์์ง๋ฅผ ๋ณด๋
์ข ๋ฃ ๋ฉ์์ง๋ ํ๋ ์์ผ๋ก ์ ๋ฌ๋๋ฉฐ, HTTP ํค๋๋ ํ์ํ์ง ์์
- ์๋ฒ ์ธก: ์ข ๋ฃ ์๋ต (Close Response)
์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์ข ๋ฃ ์์ฒญ์ ์๋ฝํ๊ณ ์๋ต์ ๋ณด๋ผ ๋๋ ๋ง์ฐฌ๊ฐ์ง๋ก close ๋ฉ์์ง๋ฅผ ์ ์ก
https://datatracker.ietf.org/doc/html/rfc6455
RFC 6455: The WebSocket Protocol
The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The security model used for this is the origin-based security mode
datatracker.ietf.org
WebSocket ๊ตฌํ ๋ฐฉ๋ฒ
1. WebSocket Upgrade, Connection ํค๋ Nginx์์ ํ์ฉํ๋๋ก ์ฒ๋ฆฌ
# WebSocket ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์ค์
location /back/api/ws/ {
proxy_pass http://127.0.0.1:8080; # WebSocket ์๋ฒ๊ฐ ์คํ ์ค์ธ ๋ก์ปฌ ํฌํธ
proxy_http_version 1.1; # WebSocket ์ฐ๊ฒฐ์ ํ์ํ HTTP ๋ฒ์
proxy_set_header Upgrade $http_upgrade; # WebSocket Upgrade ํค๋ ์ฒ๋ฆฌ
proxy_set_header Connection 'upgrade'; # WebSocket ์ฐ๊ฒฐ์ ์ํ Connection ํค๋ ์ฒ๋ฆฌ
proxy_set_header Host $host; # ํธ์คํธ ํค๋ ์ ๋ฌ
proxy_set_header X-Real-IP $remote_addr; # ํด๋ผ์ด์ธํธ IP ์ฃผ์ ์ ๋ฌ
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # ํด๋ผ์ด์ธํธ IP ์ ๋ฌ
proxy_set_header X-Forwarded-Proto $scheme; # ํ๋กํ ์ฝ ์ ๋ฌ (http ๋๋ https)
}
2. ๋ฐฑ์๋ ์ฝ๋
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/topic");
registry.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("", "http://localhost:3000").withSockJS();
}
}
@Component
@RequiredArgsConstructor
public class WebSocketEventListener {
private final SimpMessagingTemplate messagingTemplate;
private final LandingService landingService;
@EventListener
public void handleSubscriptionEvent(SessionSubscribeEvent event) {
String destination = event.getMessage().getHeaders().get("simpDestination").toString();
// ํน์ ํ ํฝ ๊ตฌ๋
์ ์ด๊ธฐ ๋ฐ์ดํฐ ์ ์ก
if (destination.startsWith("/topic/user/")) {
String userId = destination.split("/")[3];
LandingInfos landingInfos = landingService.getAllRelatedInfo(Long.parseLong(userId));
LandingStatus stage = LandingStatus.from(landingInfos);
String state = stage.toString().toLowerCase();
messagingTemplate.convertAndSend("/topic/user/" + userId + "/married-status", state);
}
}
}
- ๋ถ๋ถ ์ค ํ ์ฌ๋์ด๋ผ๋ ์ ๋ณด๋ฅผ ์ฐ๊ฒฐํ๊ฑฐ๋ ๊ทธ๋ฌ๋ฉด ๊ตฌ๋ ํ๊ณ ์๋ ์ฌ์ฉ์์๊ฒ ์ํ ์ ์ก

- ์ด ํ์ ์ ๊ทธ๋ ์ด๋ ํด์ผ ํ๋ ๋ถ๋ถ
์ฌ์ง, ๋ด์ฉ๋ ์ ์กํด์ ์ค์๊ฐ์ผ๋ก ๋ณ๊ฒฝ๋๋ ์ฌ์ง์ด๋ ๊ฒฐํผ ๊ธฐ๋ ์ผ ๋ด์ฉ๋ ํ์ธํ ์ ์๋๋ก ํ๊ธฐ