springboot 에서 웹소켓으로 채팅을 하려고 했는데 자꾸 에러가 난다..
웹소켓은 뭔가 ??
여기에서 WebSocket 에 대해 우선 알아보도록 하자.
1. WebSocket 이란 ?
Spring Boot WebSocket은 양방향(실시간) 통신을 가능하게 하는 프로토콜을 Spring Boot에서 지원하는 기능이다.
일반적인 HTTP 요청/응답 방식과 달리 WebSocket은 지속적인 연결을 유지하면서 실시간 데이터를 주고받을 수 있는 프로토콜 이다.
■ WebSocket의 특징
✅ 실시간 양방향 통신
→ 서버와 클라이언트가 한 번 연결을 맺으면 지속적으로 데이터를 주고받을 수 있음
→ 채팅, 알림, 실시간 주식 데이터, 게임 등에 활용
✅ HTTP보다 효율적인 데이터 전송
→ HTTP는 매 요청마다 새로운 연결을 맺지만, WebSocket은 한 번 연결하면 유지됨
→ 네트워크 리소스를 줄이고 속도를 향상시킴
✅ Full-Duplex 통신
→ 클라이언트와 서버가 동시에 데이터를 주고받을 수 있음
✅ Event-Driven 방식
→ 이벤트가 발생할 때마다 데이터가 푸시됨 (예: 새로운 채팅 메시지 도착 시 바로 표시)
■ WebSocket 사용 사례
✅ 실시간 채팅
✅ 실시간 알림 (푸시 알림, 이메일 알림 등)
✅ 라이브 데이터 업데이트 (주식, 날씨, 스포츠 경기 등)
✅ 온라인 멀티플레이 게임
■ 방식 정리
WebSocket 핸들러 | TextWebSocketHandler를 사용하여 WebSocket 구현 |
STOMP + SockJS | 메시징 프로토콜(STOMP)과 SockJS를 활용해 보다 안정적으로 WebSocket 지원 |
SockJS | WebSocket을 지원하지 않는 환경에서도 대체할 수 있도록 제공 |
Spring Boot WebSocket은 실시간 기능이 필요한 서비스에서 강력한 도구이다.
STOMP + SockJS를 함께 사용하는 것이 일반적이며, @MessageMapping과 @SendTo를 활용하면 보다 편리하게 메시지를 주고받을 수 있다.
어떤 방식으로 구현할지 고민 중이라면?
👉 채팅 서비스나 알림 시스템이라면 STOMP + SockJS를 추천! 🚀
하지만 나는 일반적인 WebSocket 핸들러를 사용했다. 우선 처음 찾아보는 방법이 웹소켓 핸들러였고 이미 웹소켓 핸들러에 대한 환경설정을 미리 끝마쳤기 때문이다.
하지만 테스트 했을때 로컬에서는 잘 되었지만 실제 서버 업로드 후 릴리즈 모드로 테스트 해보았는데 웹소켓 nginx 리다이렉트 부분에서 문제가 생긴 듯 하다
그래서 구글링을 해보았다.
문제는 분명 nginx 에서 발생하는 것 같았다.. 왜냐하면 로컬에서는 잘 되었으니깐..!!
그래서 nginx 설정 관련해서 집중적으로 찾아보았다
2. Nginx 란 ?
**Nginx(엔진엑스)**는 고성능의 HTTP 웹 서버이자 리버스 프록시(reverse proxy) 서버이다.
처음에는 높은 동시 접속 처리를 위해 개발되었으며, 현재는 로드 밸런서, 캐시 서버, 스트리밍 서버 등 다양한 용도로 활용된다.
■ Nginx의 주요 특징
✅ 빠르고 가벼운 웹 서버
→ C언어로 작성되어 성능이 뛰어나고, 낮은 리소스로도 많은 요청을 처리 가능
✅ 비동기 & 이벤트 기반 구조
→ 하나의 프로세스가 여러 요청을 동시에 처리할 수 있어 동시 연결(Concurrency) 처리에 강함
✅ 리버스 프록시 기능
→ 클라이언트 요청을 백엔드 서버(Apache, Node.js, Spring Boot 등)로 전달하는 리버스 프록시 역할 수행
✅ 로드 밸런싱 지원
→ 여러 서버에 요청을 분배하여 부하를 균등하게 분산할 수 있음
✅ 정적 파일 제공 최적화
→ HTML, CSS, JS, 이미지 등의 정적 콘텐츠를 빠르게 제공
✅ SSL/TLS 지원
→ HTTPS 트래픽을 처리하고 Let's Encrypt 등의 SSL 인증서 적용 가능
✅ 캐싱 기능 제공
→ 반복되는 요청에 대해 캐싱을 설정하여 성능 향상
■ Nginx 기본적인 동작 방식
Nginx는 클라이언트 요청을 받아 백엔드 서버로 전달하거나 정적 파일을 직접 제공하는 방식으로 동작합니다.
(1) 기본적인 요청 흐름
클라이언트 요청 → Nginx → 정적 파일 응답 OR 백엔드 서버 전달 → 응답 반환
✅ 정적 파일 서빙
- 클라이언트가 index.html 요청 시, Nginx가 직접 파일을 반환
✅ 리버스 프록시
- 클라이언트 요청을 Nginx가 받고, 백엔드 서버(Node.js, Django, Spring Boot 등)로 전달
✅ 로드 밸런싱
- 여러 백엔드 서버 중 하나로 요청을 분산하여 서버 부하를 줄임
■ Nginx 사용 사례
✅ 정적 웹 사이트 배포 (HTML, CSS, JavaScript 서빙)
✅ Spring Boot, Django, Node.js 등의 백엔드와 연동 (리버스 프록시)
✅ 로드 밸런싱을 통한 부하 분산
✅ HTTPS(SSL/TLS) 적용하여 보안 강화
✅ API Gateway 역할 수행
Nginx는 가볍고 빠른 웹 서버로, 리버스 프록시와 로드 밸런싱까지 지원하는 강력한 서버 소프트웨어이다.
📌 어떤 경우에 Nginx를 사용할까?
- 정적 파일을 빠르게 서빙하고 싶을 때
- Spring Boot, Django, Node.js 등의 API 서버 앞단에 리버스 프록시를 둘 때
- 부하를 분산하는 로드 밸런서를 구축할 때
- HTTPS(SSL/TLS) 적용이 필요할 때
이렇게 nginx 를 알아보았다. 그렇다면 나의 nginx 환경 설정은 어떻게 해야할까?
location /bmt/chat {
proxy_pass http://localhost:8085/chat; # 실제 WebSocket 서버의 주소
proxy_http_version 1.1; proxy_set_header
Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr; # 필요시 추가
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 필요시 추가
}
위와 같은 해결방법을 알아내었다
여기에서 위와 같이
Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
이 2개의 구문을 추가해주었더니 잘 통신이 됐다 !!!
![](https://t1.daumcdn.net/keditor/emoticon/friends1/large/003.gif)
그럼 위의 2가지 는 무엇을 의미하는 것일까 !!??
1. Upgrade $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
✅ 설명:
- HTTP 요청 헤더의 Upgrade 값을 $http_upgrade 변수로 설정합니다.
- $http_upgrade는 클라이언트가 보낸 Upgrade 헤더 값을 저장하는 변수입니다.
- WebSocket 또는 HTTP/2 연결을 사용할 경우, 클라이언트가 **"이 연결을 업그레이드하고 싶다"**고 요청하면, 이를 백엔드 서버로 전달합니다.
예시:
WebSocket을 사용하면 클라이언트가 다음과 같은 요청을 보냅니다.
- $http_upgrade 값은 "websocket"이 되고, 이를 백엔드 서버로 전달하는 역할을 합니다.
2. proxy_set_header Connection "Upgrade"
proxy_set_header Connection "Upgrade";
✅ 설명:
- Connection 헤더를 "Upgrade"로 설정하여 클라이언트와 백엔드 서버 간의 업그레이드 요청을 유지합니다.
- 일반적으로 HTTP는 요청을 보낸 후 연결을 닫지만, WebSocket은 지속적인 연결을 유지해야 하므로 업그레이드 요청을 명확히 전달해야 합니다.
📌 Connection 헤더는 기본적으로 "keep-alive"이지만, WebSocket에서는 "Upgrade"로 변경하여 지속적인 연결을 보장합니다.
이 설정이 필요한 이유
- proxy_http_version 1.1; → WebSocket은 HTTP/1.1 이상에서만 지원됨
- proxy_set_header Upgrade $http_upgrade; → 클라이언트가 요청한 Upgrade 헤더 값을 백엔드 서버로 전달
- proxy_set_header Connection "Upgrade"; → 연결을 업그레이드하여 지속적인 통신 가능
그래서 결국 제대로 통신이 가능했던 것 같다. !!!
'Springboot' 카테고리의 다른 글
vscode_ SpringBoot 프로젝트 만들기 (0) | 2024.08.20 |
---|---|
Springboot -SSE ( 로컬에서는 실시간 o / https nginx 서버에서는 실시간 x) (0) | 2024.06.23 |
springboot https 적용기 (0) | 2024.06.05 |
Springboot_ Redis SSE 작업 (0) | 2024.06.02 |