본문 바로가기
C.W.K.
Stream
Lesson 02 of 07 · published

WebSocket 위의 요청과 응답

~13 min · protocol, correlation-id, promises

Level 0Poller
0 XP0/60 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

WebSocket 의 기본은 보내고 잊기야

프로토콜은 ‘이 메시지에 대한 응답을 기다려’라는 의미를 제공하지 않아. 모든 메시지가 독립적이지. 사용자 데이터를 가져오거나 설정을 저장하는 등 클라이언트가 결과를 확인해야 한다면 요청과 응답의 의미를 직접 만들어야 해. 이때 상관관계 ID 를 추가해. 클라이언트가 고유 ID 를 정하고 서버가 그대로 돌려주면 클라이언트가 둘을 짝지을 수 있어.

Promise 로 감싼 요청

클라이언트에서는 작은 Promise 래퍼를 두면 편해. await ws.request('user.get', {id: 'x'}) 가 응답 데이터를 돌려주는 모습이지. 내부에서는 UUID 를 만들고 결과 처리기를 등록한 뒤 메시지를 보내고 기다려. 응답이 오지 않는 것도 가능한 결과이므로 반드시 시간 제한을 넣어.

Code

Promise 로 감싼 요청·javascript
const pending = new Map(); // id -> { resolve, reject, timer }

function request(ws, type, data, timeoutMs = 10_000) {
  return new Promise((resolve, reject) => {
    const id = crypto.randomUUID();
    const timer = setTimeout(() => {
      pending.delete(id);
      reject(new Error(`timeout: ${type}`));
    }, timeoutMs);
    pending.set(id, { resolve, reject, timer });
    ws.send(JSON.stringify({ id, type, data }));
  });
}

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.id && pending.has(msg.id)) {
    const entry = pending.get(msg.id);
    pending.delete(msg.id);
    clearTimeout(entry.timer);
    if (msg.type === 'error') entry.reject(new Error(msg.message));
    else                      entry.resolve(msg.data);
    return;
  }
  // Unsolicited event — push, not response
  handleEvent(msg);
};

// Usage
const user = await request(ws, 'user.get', { id: '123' });
서버에서 id 를 그대로 돌려주기·python
async def handle(ws, msg):
    rid = msg.get('id')
    typ = msg.get('type')
    data = msg.get('data', {})
    try:
        result = await dispatch(typ, data)
        await ws.send_json({
            'id': rid,
            'type': f'{typ}.response',
            'data': result,
        })
    except Exception as e:
        await ws.send_json({
            'id': rid,
            'type': 'error',
            'code': type(e).__name__,
            'message': str(e),
        })

External links

Exercise

request() 와 받은 id 를 그대로 돌려주는 서버를 만들어. 요청 5개를 동시에 보내 응답 순서가 뒤섞여도 올바르게 짝지어지는지 확인해. 요청 하나만 서버에서 15초 동안 붙잡아 두고 클라이언트가 10초에 시간 초과를 내는 동안 나머지는 정상 완료되는지도 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.