WebSocket이란?
HTTP는 클라이언트가 요청하면 서버가 응답하는 구조이다.
반면 WebSocket은 클라이언트
서버 간에 양방향 통신이 가능하게 해주는 프로토콜이다.
•
서버가 클라이언트에게 실시간으로 메세지를 전송한다.
•
연결을 유지하며 데이터를 주고받는다. (HTTP보다 빠르다)
NestJS에서의 WebSocket
NestJS는 @nestjs/websockets 패키지를 설치하여 WebSocket을 쉽게 사용할 수 있게 해준다.
@WebSocketGateway 데코레이터를 통해 해당 클래스를 WebSocket 서버로 등록해준다.
@WebSocketGateway(port?: number, options?: GatewayOptions)
export class ExampleGateway {
}
TypeScript
복사
옵션 | 설명 | 예시 |
port | 게이트웨이가 바인딩될 포트 번호
생략 시 HTTP 서버와 같은 포트를 사용한다. | @WebSocketGateway(3001) |
namespace | 특정 namespace로 클라이언트를 구분한다.
클라이언트들이 다른 경로(/chat, /notification 등)로 접속하게끔 나누는 단위 | @WebSocketGateway({ namespace: '/chat' }) |
cors | socket.io 서버 CORS 설정을 할 수 있다.
NestJS HTTP 서버의 CORS 설정과는 별개이다. | @WebSocketGateway({ cors: { origin: '*' } }) |
transports | 클라이언트 | @WebSocketGateway({ transports: ['websocket'] }) |
path | 커스텀 path로 WebSocket 서버를 노출할 수 있음 | @WebSocketGateway({ path: '/ws' }) |
socket.io 서버의 옵션
NestJS는 WebSocket을 지원할 때 내부적으로 socket.io 를 사용한다.
@WebSocketGateway 데코레이터의 옵션으로 들어가는 cors설정은 socket.io 서버 생성자에 전달되는 것이다.
@WebSocketGateway({ cors: { origin: '*' } })
위 코드는
const io = new Server(httpServer, {
cors: {
origin: '*'
}
});
이 코드와 같다.
TypeScript
복사
transports 옵션
transports 옵션에는 크게 polling과 websocket이 있다.
기본 옵션은 ['polling', 'websocket'] 으로 처음에는 polling으로 시작해서 가능하면 websocket으로 업그레이드하는 것이다.
만약 웹소켓만 쓰고 싶다면 [’websocket’]으로 polling만 할거라면 [’polling’]으로 설정하면 된다.
방화벽이나 프록시 문제로 웹소켓이 연결이 안 될 수도 있어 운영단계에서는 보통 기본 옵션을 사용한다.
연습 예제 코드
import {
ConnectedSocket,
MessageBody,
OnGatewayConnection,
OnGatewayDisconnect,
SubscribeMessage,
WebSocketGateway,
WebSocketServer,
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
// ExampleGateway를 WebSocket 서버로 등록
// 내부적으로 socket.io 서버 인스턴스를 생성
@WebSocketGateway({
namespace: '/example',
transports: ['websocket'],
cors: {
origin: '*',
},
})
export class ExampleGateway
implements OnGatewayConnection, OnGatewayDisconnect
{
// Gateway 클래스에 Socket.IO의 서버 인스턴스를 주입해주는 데코레이터
// 클라이언트에게 직접 이벤트를 보내는 등 작업을 수행
@WebSocketServer() io: Server;
handleConnection(client: Socket): any {
const data = client.handshake.query;
console.log(`client 연결 : ${client.id}, message: ${data.name}`);
}
handleDisconnect(client: Socket): any {
console.log(`client 연결 끊김 : ${client.id}`);
}
@SubscribeMessage('message')
handleTestMessage(
@MessageBody() message: string,
@ConnectedSocket() client: Socket,
) {
const username = client.handshake.query.name[0];
const sendMessage = `${username} : ${message}`;
this.io.emit('message', sendMessage);
}
}
TypeScript
복사