NestJS WebSockets - Gateways

GGAE99·2023년 11월 3일
0

NestJS 공식 문서

목록 보기
32/33
post-thumbnail

Gateways

다른 곳에서 이야기 된 대부분의 개념, 종속성 주입, 데코레이터, 예외 필터, 파이프, 가드 및 인터셉터와 같은 개념은 게이트웨이에도 동일하게 적용됩니다. Nest는 구현 세부 정보를 추상화하여 동일한 구성 요소가 HTTP 기반 플랫폼, 웹소켓 및 마이크로 서비스에서 실행될 수 있도록합니다. 이 섹션에서는 Nest에 특화된 WebSockets와 관련된 측면을 다룹니다.

Nest에서 게이트웨이는 단순히 @WebSocketGateway() 데코레이터로 처리 된 클래스입니다. 기술적으로 게이트웨이는 플랫폼에 독립적이며 어댑터가 생성되면 어떤 WebSocket 라이브러리와도 호환됩니다. 두 가지 WS 플랫폼 socket.io 및 ws이 기본적으로 지원됩니다. 여러분의 요구에 가장 적합한 것을 선택할 수 있습니다. 또한 필요한 경우 이 가이드를 따라 직접 어댑터를 만들 수 있습니다.

Hint!
게이트웨이는 프로바이더로 처리할 수 있으며 클래스 생성자를 통해 종속성을 주입할 수 있음을 의미합니다. 또한 게이트웨이는 다른 클래스(프로바이더 및 컨트롤러)에 의해 주입 될 수도 있습니다.

Installation

웹소켓 기반 애플리케이션을 구축하기 위해 먼저 필요한 패키지를 설치하세요.

$ npm i --save @nestjs/websockets @nestjs/platform-socket.io

Overview

일반적으로 각 게이트웨이는 HTTP 서버와 동일한 포트에서 수신 대기하고 있습니다. 앱이 웹 애플리케이션이 아니거나 포트를 수동으로 변경하지 않은 한이 기본 동작을 수정할 수 있습니다. 이 기본 동작을 수정하려면 @WebSocketGateway(80) 데코레이터에 인수를 전달하여 사용할 포트 번호를 지정합니다. 또한 게이트웨이에서 사용할 네임스페이스를 설정할 수 있습니다.

@WebSocketGateway(80, { namespace: 'events' })

Warning!!
게이트웨이는 기존 모듈의 프로바이더 배열에서 참조 될 때까지 생성되지 않습니다.

@WebSocketGateway() 데코레이터의 두 번째 인수를 사용하여 소켓 생성자에 지원되는 옵션을 전달할 수 있습니다.

@WebSocketGateway(81, { transports: ['websocket'] })

게이트웨이는 이제 수신중 입니다만, 아직 메세지에 대한 처리가 없습니다.
events메시지를 처리하고 정확히 동일한 데이터로 사용자에게 응답하는 핸들러를 만들어 보겠습니다.

// events.gateway.ts
@SubscribeMessage('events')
handleEvent(@MessageBody() data: string): string {
  return data;
}

Hint!
@SubscribeMessage()@MessageBody() 데코레이터는 @nestjs/websockets 패키지에서 가져옵니다.

게이트웨이가 만들어진 후에는 모듈에서 등록할 수 있습니다.

//events.module.ts
@Module({
  providers: [EventsGateway]
})
export class EventsModule {}

속성 키를 데코레이터에 전달하여 수신 메시지 본문에서 추출할 수도 있습니다.

//events.gateway.ts
@SubscribeMessage('events')
handleEvent(@MessageBody('id') id: number): number {
  // id === messageBody.id
  return id;
}

데코레이터를 사용하지 않으려면 다음 코드도 기능적으로 동일합니다.

//events.gateway.ts
@SubscribeMessage('events')
handleEvent(client: Socket, data: string): string {
  return data;
}

위의 예에서 handleEvent() 함수는 두 개의 인수를 사용합니다. 첫 번째는 플랫폼별 소켓 인스턴스이고 두 번째는 클라이언트로부터 수신한 데이터입니다. 그러나 이 접근 방식은 각 단위 테스트에서 소켓 인스턴스를 모의화해야하기 때문에 권장되지는 않습니다.

events 메시지를 수신하면 핸들러는 네트워크를 통해 보낸 데이터와 동일한 데이터로 승인을 보냅니다. 또한 client.emit() 메서드를 사용하여 라이브러리별 접근 방식을 사용하여 메시지를 보낼 수 있습니다. 연결된 소켓 인스턴스에 액세스하려면 @ConnectedSocket() 데코레이터를 사용하십시오.

//events.gateway.ts
@SubscribeMessage('events')
handleEvent(
  @MessageBody() data: string,
  @ConnectedSocket() client: Socket,
): string {
  return data;
}

Hint!
@ConnectedSocket() 데코레이터는 @nestjs/websockets 패키지에서 가져옵니다.

그러나 이 경우에는 인터셉터를 활용할 수 없습니다. 사용자에게 응답하지 않으려면 return문을 건너 뛰거나 명시적으로 "거짓" 값을 반환하면 됩니다. (예: undefined를 반환)

이제 클라이언트가 다음과 같이 메시지를 보낼 때,

socket.emit('events', { name: 'Nest' });

handleEvent() 메서드가 실행됩니다. 이 핸들러 내에서 보낸 메시지를 수신하려면 클라이언트는 해당 확인 리스너를 첨부해야합니다.

socket.emit('events', { name: 'Nest' }, (data) => console.log(data));
// (data) => console.log(data)); => 리스너

Multiple responses

확인은 한 번만 전달됩니다. 또한 네이티브 웹소켓 구현에서는 지원되지 않습니다. 이 제한을 해결하기 위해 두 개의 속성으로 구성된 객체를 반환할 수 있습니다. 이 객체에는 event라는 발생 이벤트의 이름과 클라이언트에게 전달해야하는 데이터인 data가 포함됩니다.

//events.gateway.ts
@SubscribeMessage('events')
handleEvent(@MessageBody() data: unknown): WsResponse<unknown> {
  const event = 'events';
  return { event, data };
}

Hint!
WsResponse 인터페이스는 @nestjs/websockets 패키지에서 가져옵니다.

Warning!!
data 필드가 ClassSerializerInterceptor에 의존하는 경우, 일반 JavaScript 객체 응답을 무시하기 때문에 WsResponse를 구현하는 클래스 인스턴스를 반환해야합니다.

수신된 응답을 수신하려면 클라이언트는 다른 이벤트 리스너를 적용해야합니다.

socket.on('events', (data) => console.log(data));

Asynchronous responses

메시지 핸들러는 동기적 또는 비동기적으로 응답할 수 있습니다. 따라서 async 메서드를 지원합니다. 메시지 핸들러는 Observable을 반환할 수도 있으며, 이 경우 스트림이 완료 될 때까지 결과 값이 생성됩니다.

// events.gateway.ts
@SubscribeMessage('events')
onEvent(@MessageBody() data: unknown): Observable<WsResponse<number>> {
  const event = 'events';
  const response = [1, 2, 3];

  return from(response).pipe(
    map(data => ({ event, data })),
  );
}

위의 예에서 메시지 핸들러는 3번 응답할 것입니다 (배열에서 각 항목별로).

Lifecycle hooks

세 가지 유용한 생명 주기 후크가 있습니다.

  • OnGatewayInit: afterInit() 메서드를 구현하도록 강제합니다. 라이브러리별 서버 인스턴스를 인수로 취하며 필요한 경우 나머지 인수를 분산시킵니다.
  • OnGatewayConnection: handleConnection() 메서드를 구현하도록 강제합니다. 라이브러리별 클라이언트 소켓 인스턴스를 인수로 취합니다.
  • OnGatewayDisconnect: handleDisconnect() 메서드를 구현하도록 강제합니다. 라이브러리별 클라이언트 소켓 인스턴스를 인수로 취합니다.

Hint!
각 생명 주기 인터페이스는 @nestjs/websockets 패키지에서 노출됩니다.

Server

가끔은 원시, 플랫폼별 서버 인스턴스에 직접 액세스하고 싶을 수 있습니다. 이 객체에 대한 참조는 afterInit() 메서드의 인수로 전달되며 (OnGatewayInit 인터페이스) 나머지 인수를 퍼뜁니다. 또 다른 옵션은 @WebSocketServer() 데코레이터를 사용하는 것입니다.

@WebSocketServer()
server: Server;

@WebSocketServer() 데코레이터는 @nestjs/websockets 패키지에서 가져옵니다.

Nest는 서버 인스턴스가 사용 가능한 경우 자동으로 이 속성에 서버 인스턴스를 할당합니다.

웹소켓이란?

클라이언트와 서버(브라우저와 서버)를 연결하고 실시간으로 통신이 가능하도록 하는 첨단 통신 프로토콜이다. 웹소켓은 하나의 TCP 접속에 전이중(duplex) 통신 채널을 제공한다. 쉽게 말해, 웹소켓은 Socket Connection을 유지한 채로 실시간으로 양방향 통신 혹은 데이터 전송이 가능한 프로토콜이다.

웹소켓과 HTTP의 차이

특성웹소켓 (WebSocket)HTTP (Hypertext Transfer Protocol)
프로토콜양방향 통신을 지원하는 실시간 프로토콜단방향 요청 및 응답을 처리하는 프로토콜
연결 상태계속 유지되는 연결 (Connectionful)비연결 상태 (Connectionless)
헤더작은 오버헤드, 헤더 크기 작음큰 오버헤드, 많은 헤더 정보 포함
지원 기술실시간 채팅, 게임, 주식 시세 등에 사용웹 페이지 로드, 파일 다운로드, REST API
단방향/양방향양방향 통신 (Full-duplex)단방향 요청 및 응답 (Half-duplex)
포트HTTP와 동일한 포트 사용 (80 또는 443)HTTP는 기본적으로 80 포트를 사용, HTTPS는 443 포트를 사용
상태 코드상태 코드 없음 (클라이언트/서버 간 상태 정보를 유지하지 않음)HTTP 상태 코드 (e.g., 200 OK, 404 Not Found)
데이터 형식텍스트 또는 이진 데이터 전송 가능주로 HTML, JSON, XML, 이미지 등 다양한 데이터 형식 전송

참고할 사이트

0개의 댓글