Error log

WebSocket 연결 오류 발생 및 해결 과정

sowon02 2025. 11. 17. 15:04

오늘은 프로젝트에서 구현해둔

WebSocket/STOMP 기능을 테스트하는 과정에서 여러 가지 예상치 못한 오류들이 발생하여,
해당 문제들을 문제 상황 → 원인 분석 → 해결 과정 순서로 정리하였습니다.

 

이번 오류는 단순한 코드 문제가 아니라, 보안 설정, CORS, SockJS 정책, Handshake 옵션들이 서로 충돌하면서 발생한 케이스였고, 특히 Spring Boot 3.x 환경에서 자주 발생할 수 있는 유형이었습니다.

아래는 실제로 테스트 중 발생했던 에러들입니다.

WebSocket connection to 'ws://<server>:8080/ws/websocket' failed
POST /ws/... xhr_streaming?... 500 (Internal Server Error)
GET /ws/iframe.html 404 (Not Found)
[WebSocket] Secure handshake required but connection is not secure
When allowCredentials is true, allowedOrigins cannot contain the special value "*"
WebSocket connection timeout after 10 seconds

 

이러한 오류로 인해 STOMP CONNECT 프레임이 서버에 전달되지 않는 문제가 계속되었으며,
결과적으로 WebSocket 연결 자체가 정상적으로 성립하지 않는 상황이었습니다.


1. 문제 상황

  • WebSocket 핸드쉐이크는 이루어지는 것처럼 보였지만, STOMP CONNECT 프레임이 서버에 도달하지 않음
  • 콘솔에서는 다음과 같은 오류가 반복적으로 출력됨
    (iframe.html 404, XHR-streaming 500, connection failed 등)
  • /ws/info 는 정상적으로 응답하므로 엔드포인트는 열려 있었음 → 그러나 실제 STOMP 연결은 실패하는 상태

2. 원인 분석

에러 메시지를 기반으로 하나씩 확인한 결과, 다음 세 가지 설정이 서로 충돌하고 있었습니다.

 

- 1) Secure Handshake 강제 옵션이 HTTP 환경과 충돌

app.websocket.require-secure-handshake=true 때문에
HTTPS가 아닌 모든 WebSocket 연결이 서버에서 즉시 거부되고 있었습니다.

 

- 2) Spring CORS 설정 충돌 

Spring Boot 3.x에서는 아래 조합이 금지되어 있습니다:

  • setAllowedOrigins("*")
  • allowCredentials(true)

이 설정은 다음 오류를 유발하였습니다:

When allowCredentials is true, allowedOrigins cannot contain the special value "*"

즉, CORS에서 인증 정보(Authorization/JWT)가 전달될 때

"*"와 함께 사용할 수 없습니다. 

 

- 3) SockJS iframe fallback 비활성화 

로그 : 

Iframe support is disabled when an origin check is required
GET /ws/iframe.html 404

이 오류는 실제로는 “오류”가 아니라, SockJS가 iframe fallback을 비활성화했기 때문에 발생하는 정상 로그였습니다.
fallback transport는 비활성 상태였고, 프론트에서 transport 명시가 필요했습니다.


3. 해결 과정 

문제의 원인을 각각 분리한 뒤, 다음과 같이 해결했습니다.

 

- 1) Secure Handshake 비활성화

app.websocket.require-secure-handshake=false

 

- 2) CORS 정책 수정

.setAllowedOriginPatterns("*") // allowedOrigins("*") → 변경

 

- 3) SockJS transport 명시 (프론트)

new SockJS(url, null, {
  transports: ['websocket', 'xhr-streaming', 'xhr-polling']
});

이 세 가지를 수정한 뒤 다시 테스트한 결과, STOMP CONNECT 프레임이 정상적으로 서버에 도달하고
구독(/topic/...) 및 실시간 브로드캐스트가 모두 정상 동작했습니다


4. 결론 

오늘은 WebSocket 테스트 과정에서 발생한 여러 오류를 정리하고, 각 오류의 문제와 원인, 해결 방법을 단계별로 정리해보았습니다. 최종적으로 문제는 코드 자체가 아니라, 보안 설정(secure handshake), Spring CORS 정책, SockJS fallback 정책이 서로 충돌하면서 WebSocket 연결을 차단하던 것이었습니다.