[stompjs] STOMP CONNECT 전송 버그

임기준·2025년 6월 6일
0

문제 내용

stompjs라이브러리를 사용하여 웹 상에서 websocket stomp 전송에 문제가 없었는데 안드로이드에서 websocket 연결 후 stomp CONNECT frame 에 대해 요청한 것으로 보이는 데 서버상에서는 아무런 요청이 오지 않는 문제가 발생했다.

STOMP CONNECT 구조

stomp에서 CONNECT 메세지 구조는 아래의 예제와 비슷하다.

COMMAND
header1:value1
header2:value2
...
//빈줄 \n
<optional body>
\0	<-- NULL byte

이 CONNECT 메시지를 서버가 정상적으로 수신하고 인증을 통과하면, 서버는 CONNECTED 프레임을 반환하게 되어 있는데 우선 서버상의 문제가 아닌지 확인이 필요하다.

서버 테스트

postman으로 stomp를 진행하려고 하는데 NULL 바이트 전송이 좀 애매해서 대안으로 websocat(CLI도구)를 사용하여 확인했다.

websocat ws://localhost:8082/ws-stomp
CONNECT
accept-version:1.2
heart-beat:10000,10000

^@
CONNECTED version:1.2 heart-beat:0,0 // <-- 응답

참고) Mac에서 NULL 바이트 입력하는 방법
1. Control + V, 그 다음 Control + @ 입력

  • ^V^@ 이렇게 표시되면 정상입니다.
  • Control + Shift + 2 로도 ^@ 입력 가능

응답이 정상임을 확인했다.

클라이언트 테스트

stompjs를 사용하는 기본 예제는 아래와 같다.

import { Client } from '@stomp/stompjs';

const client = new Client({
  brokerURL: 'ws://localhost:8082/ws-stomp',
  connectHeaders: {
    Authorization: 'Bearer YOUR_JWT_TOKEN',
    'Content-Type': 'application/json',
  },
  onConnect: () => {
    console.log('✅ STOMP connected');
  },
  onStompError: frame => {
    console.error('❌ STOMP error:', frame);
  },
  debug: str => {
    console.log('STOMP Debug', str); // 디버깅 로그
  }
});

client.activate();

debug 에서 CONNECT 로 출력되는 모습에서 빈줄과 NULL바이트가 없어 보였다.

 [LOG]  STOMP Debug: >>> CONNECT
Authorization:Bearer {JWT 토큰}
Content-Type:application/json
accept-version:1.2,1.1,1.0
heart-beat:10000,10000
// 빈줄이 없음

debug 에서 아래와 같이 수정했을 때

debug: function (str) {
  console.log('STOMP Debug', JSON.stringify(str));
}

NULL 바이트가 포함되어 있다면 로그 맨 끝이 이렇게 보여야 한다.

"STOMP Debug >>> CONNECT\naccept-version:1.2\nheart-beat:10000,10000\n...\n\u0000"

\u0000 ← 이게 바로 NULL 바이트

만약 위의 NULL바이트가 보이지 않는다면

  1. 아래와 같이 메세지 전송시 NULL 바이트를 추가한다.
import { Client } from '@stomp/stompjs';
import { Buffer } from 'buffer';

global.Buffer = Buffer; // React Native 환경에서 Buffer 사용을 위해 설정

const client = new Client({
  brokerURL: 'ws://yourserver/ws',
  connectHeaders: {
    Authorization: 'Bearer YOUR_JWT_TOKEN',
    'Content-Type': 'application/json',
  },
  debug: (str) => {
    console.log('[STOMP DEBUG]', str);
  },
  webSocketFactory: () => {
    const ws = new WebSocket('ws://yourserver/ws');
    const originalSend = ws.send;
    ws.send = (data) => {
      if (typeof data === 'string') {
        const encoder = new TextEncoder();
        const uint8Array = encoder.encode(data);
        originalSend.call(ws, uint8Array);
      } else {
        originalSend.call(ws, data);
      }
    };
    return ws;
  },
});

client.activate();
  1. 아래의 사이트에서 버그 수정안에 대해 이야기하고 있다.
        const client = new Client({
          brokerURL: `${env.WS_URL}/ws-stomp`,
          appendMissingNULLonIncoming: true,  	
          forceBinaryWSFrames: true,			
          connectHeaders: {
              'Authorization': accessToken,
              'Content-Type': 'application/json',
          },  
  • appendMissingNULLonIncoming : true
  • forceBinaryWSFrames : true

위 2개의 옵션을 true로 설정하면 된다. (당연 추천은 2번이다.)

이 설정을 통해 STOMP 메시지가 바이너리 형태로 전송되며, NULL 바이트가 정확하게 포함되어 서버에서 메시지를 올바르게 처리할 수 있게 된다.

profile
openerzone

0개의 댓글