【제41회】 존재하지 않는 방에 대한 접근을 차단하라! P2P 채팅 참여 시 룸 존재 검증 및 에러 핸들링
요약
본 글은 P2P 채팅 시스템의 룸 존재 검증 및 에러 핸들링 개선 과정을 다룹니다. 기존 Signaling API가 '방 생성'과 '참여'를 구분하지 못해 비존재 방 접속 문제를 야기했습니다. 이를 해결하기 위해 클라이언트가 의도(Intent)를 명시하고, 서버는 룸 존재 여부를 엄격히 검증하여 안전한 에러 처리를 구현했습니다.
핵심 포인트
- API 엔드포인트에서 '생성'과 '참여'의 의도를 분리해야 합니다.
- 클라이언트는 신규 생성인지 기존 참여인지를 나타내는 플래그를 전송해야 합니다.
- 서버는 룸 존재 여부를 검증하고, 미존재 시 명확한 에러(ROOM_NOT_FOUND)를 반환해야 합니다.
- 에러 발생 시 사용자에게 로비 화면에서 경고 메시지를 제공하는 것이 좋습니다.
안녕하세요! 2채널 호환 게시판 시스템 '츠바이채널(つゔぁいちゃんねる, 2ch.biz)' 개발 기록 제41회입니다.
지난번(제40회)까지 모바일 웹 환경에서의 소프트웨어 키보드 추적 및 헤더 고정이라는 사투를 이겨내고 스마트폰에서도 최고의 사용성을 확보했습니다.
하지만 본격적으로 P2P 채팅이 운영되고, 게시판 내에서 방 초대 URL이 오가기 시작하자 사용자들로부터 이해하기 어려운 문의가 잇따르기 시작했습니다.
'친구에게 '지금 잡담방에 있으니 와!'라는 URL을 받았는데, 입장해보니
아무도 없고 나 혼자만 있어요…'
'30분 기다려도 아무도 발언하지 않아서 친구에게 물어보니, 사실 URL 끝이 한 글자 빠져 있었대요!'
왜 존재하지 않을 리 있는 URL로 접속할 수 있게 되어 사용자들이 외로운 시간을 보내고 있었던 걸까요?
본고에서는 Signaling Server에 숨겨져 있던 '무조건 자동 생성의 함정'을 해명하고, 존재하지 않는 방으로의 접근을 확실하게 차단하는 룸 존재 검증(Room Existence Validation)과 에러 핸들링 설계를 설명합니다!
일반적인 웹 서비스라면, 존재하지 않는 URL(/room/xyz_not_exist)에 접속하면 404 Not Found가 반환되는 것이 당연합니다.
하지만 저희 P2P 채팅의 Signaling API(join 엔드포인트)에는 개발 초기 프로토타입 단계에서 작성된 **'어떤 코드'**가 그대로 남아 있었습니다.
// 【Before: 개발 초기 시그널링 코드】
app.post('/api/p2p/signal', (req, res) => {
const { action, roomId, peerId } = req.body;
...
이 코드의 문제점은 무엇이었을까요?
방을 '새로 만들 때(Create)'와 '기존 방에 참여할 때(Join)' 모두 완전히 동일한 API 엔드포인트를 사용하고 있었기 때문에, 서버 입장에서는 '이 사용자가 방을 만들려고 하는 건지, 기존 방에 들어가려고 하는 건지'를 구분할 수 없었던 것입니다.
그 결과, 다음과 같은 희극(사용자에게는 비극)이 발생했습니다.
[IMG:N]
이 문제를 해결하기 위한 설계는 명확합니다.
클라이언트가 시그널링을 보낼 때, **'신규 생성인지, 기존 참여인지'라는 의도(Intent)**를 엄격하게 선언하도록 하는 것입니다.
- 의도의 분리: '방 만들기' 폼에서는
isCreate: true를 전송하고, '참여하기' 폼이나 초대 URL 클릭 시에는isCreate: false를 전송한다. - 존재 판별:
isCreate: false로 방이 존재하지 않는 경우, Signaling Server는 메모리를 전혀 할당하지 않고ROOM_NOT_FOUND에러를 반환한다. - 안전한 롤백: 클라이언트는 에러를 수신했을 때 채팅 화면을 전개하는 대신, 로비 화면(입장 화면)에 머무르며 '지정된 방은 존재하지 않거나 종료되었습니다'라고 명확하게 경고한다.
입실 함수 joinRoom에서 자신이 방의 이니시에이터(생성자)인지를 나타내는 플래그 isInitiator를 서버로 전달합니다.
/**
* 룸 참여 처리
*/
...
// server.js: 시그널링 참여 핸들러
if (action === 'join') {
const isCreate = (payload && payload.isCreate === true);
...
이 수정 사항이 제대로 작동하는지 검증하기 위해 테스트 스크립트를 작성하여 실행했습니다.
// test_room_validation.js
const assert = require('assert');
async function runTests() {
...
테스트는 모두 통과했으며, 오타나 종료된 URL에 대한 접근이 100% 확실하게 차단됨을 입증했습니다.
'존재하지 않는 방에는 들어갈 수 없다', '오타가 나면 즉시 알려준다'—.
당연한 일처럼 보이지만, 서버리스 P2P라는 특수한 환경 하에서는 의식적으로 경계를 그리지 않으면 '친절함의 자동 생성'이 오히려 사용자 경험을 망치게 됩니다.
하지만 이 룸 존재 검증을 도입하면서, 우리는 더욱 깊은 **'P2P 특유의 좀비 방 문제'**에 직면하게 됩니다.
'방 참여자 전원이 한 번 퇴실하여 방이 소멸한 경우'
그 후, 다른 누군가가 우연히 같은 룸 ID로 방을 새로 만들었다.
그러자, 이전 방의 캐시를 가진 과거 참가자들이 전혀 관련 없는 새로운 방에 좀비처럼 난입해 버렸다!
같은 룸 ID의 '세대 교체'를 어떻게 구분할 수 있을까?
실제 서비스(Production Service): https://2ch.biz/
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기