Gateways

Gateways

κ²Œμ΄νŠΈμ›¨μ΄λŠ” @WebSocketGateway()λ°μ½”λ ˆμ΄ν„°λ‘œ 주석이 달린 ν΄λž˜μŠ€μž…λ‹ˆλ‹€. κ²Œμ΄νŠΈμ›¨μ΄λŠ” 기본적으둜 socket.io νŒ¨ν‚€μ§€λ₯Ό μ‚¬μš©ν•˜μ§€λ§Œ κΈ°λ³Έ μ›Ή μ†ŒμΌ“ κ΅¬ν˜„μ„ ν¬ν•¨ν•˜μ—¬ κ΄‘λ²”μœ„ν•œ λ‹€λ₯Έ λΌμ΄λΈŒλŸ¬λ¦¬μ™€μ˜ ν˜Έν™˜μ„±μ„ μ œκ³΅ν•©λ‹ˆλ‹€. μ—¬κΈ°.

warning 힌트 κ²Œμ΄νŠΈμ›¨μ΄λŠ” λ‹¨μˆœν•œ κ³΅κΈ‰μžμ™€ λ™μΌν•˜κ²Œ μž‘λ™ν•˜λ―€λ‘œ μƒμ„±μžλ₯Ό 톡해 μ†μ‰½κ²Œ 쒅속성을 μ£Όμž… ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ κ²Œμ΄νŠΈμ›¨μ΄λŠ” λ‹€λ₯Έ 클래슀 (κ³΅κΈ‰μž 및 컨트둀러)에 μ˜ν•΄ μ£Όμž… 될 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

Installation

λ¨Όμ € ν•„μš”ν•œ νŒ¨ν‚€μ§€λ₯Ό μ„€μΉ˜ν•΄μ•Όν•©λ‹ˆλ‹€.

@@filename()
$ npm i --save @nestjs/websockets @nestjs/platform-socket.io
$ npm i --save-dev @types/socket.io
@@switch
$ npm i --save @nestjs/websockets @nestjs/platform-socket.io

Overview

일반적으둜 앱이 μ›Ή μ‘μš© ν”„λ‘œκ·Έλž¨μ΄ μ•„λ‹ˆκ±°λ‚˜ μˆ˜λ™μœΌλ‘œ 포트λ₯Ό λ³€κ²½ν•˜μ§€ μ•Šμ€ 경우 각 κ²Œμ΄νŠΈμ›¨μ΄λŠ” HTTP μ„œλ²„κ°€ μ‹€ν–‰λ˜λŠ” 것과 λ™μΌν•œ 포트λ₯Ό μˆ˜μ‹ ν•©λ‹ˆλ‹€. @WebSocketGateway(80)λ°μ½”λ ˆμ΄ν„°μ— 인수λ₯Ό μ „λ‹¬ν•˜μ—¬ 이 λ™μž‘μ„ λ³€κ²½ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ 80은 μ„ νƒλœ 포트 λ²ˆν˜Έμž…λ‹ˆλ‹€. λ˜ν•œ λ‹€μŒ κ΅¬μ„±μœΌλ‘œ 이 κ²Œμ΄νŠΈμ›¨μ΄μ—μ„œ μ‚¬μš©ν•˜λŠ” namespaceλ₯Ό μ„€μ •ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

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

κ²½κ³  κ²Œμ΄νŠΈμ›¨μ΄λŠ” providers λ°°μ—΄ μ•ˆμ— 넣을 λ•ŒκΉŒμ§€ μ‹œμž‘λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ„€μž„ μŠ€νŽ˜μ΄μŠ€λŠ” μœ μΌν•˜κ²Œ μ‚¬μš© κ°€λŠ₯ν•œ μ˜΅μ…˜μ΄ μ•„λ‹™λ‹ˆλ‹€. 여기에 μ–ΈκΈ‰λœ λ‹€λ₯Έ 속성을 전달할 수 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 속성은 μΈμŠ€ν„΄μŠ€ν™” ν”„λ‘œμ„ΈμŠ€ λ™μ•ˆ μ†ŒμΌ“ μƒμ„±μžλ‘œ μ „λ‹¬λ©λ‹ˆλ‹€.

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

μ’‹μ•„, κ²Œμ΄νŠΈμ›¨μ΄λŠ” μ§€κΈˆ λ“£κ³  μžˆμ§€λ§Œ μš°λ¦¬λŠ” μ§€κΈˆκΉŒμ§€ λ“€μ–΄μ˜€λŠ” λ©”μ‹œμ§€λ₯Ό subscriptν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. events λ©”μ‹œμ§€λ₯Ό subscriptionν•˜κ³  λ˜‘κ°™μ€ λ°μ΄ν„°λ‘œ μ‚¬μš©μžμ—κ²Œ μ‘λ‹΅ν•˜λŠ” ν•Έλ“€λŸ¬λ₯Ό λ§Œλ“€μ–΄ λ΄…μ‹œλ‹€.

@@filename(events.gateway)
@SubscribeMessage('events')
handleEvent(client: Client, data: string): string {
  return data;
}
@@switch
@SubscribeMessage('events')
handleEvent(client, data) {
  return data;
}

info 힌트 @SubscribeMessage()λ°μ½”λ ˆμ΄ν„°λŠ” @nestjs/websockets νŒ¨ν‚€μ§€μ—μ„œ κ°€μ Έμ˜΅λ‹ˆλ‹€.

handleEvent()ν•¨μˆ˜λŠ” 두 개의 인수λ₯Ό μ·¨ν•©λ‹ˆλ‹€. μ²«λ²ˆμ§ΈλŠ” ν”Œλž«νΌ 별 μ†ŒμΌ“ μΈμŠ€ν„΄μŠ€μ΄κ³  두 λ²ˆμ§ΈλŠ” ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 받은 λ°μ΄ν„°μž…λ‹ˆλ‹€. λ©”μ‹œμ§€λ₯Ό λ°›μœΌλ©΄ λˆ„κ΅°κ°€κ°€ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 보낸 것과 λ™μΌν•œ λ°μ΄ν„°λ‘œ μŠΉμΈμ„ λ³΄λƒ…λ‹ˆλ‹€. λ˜ν•œ 라이브러리 별 μ ‘κ·Ό 방식을 μ‚¬μš©ν•˜μ—¬, 예λ₯Ό λ“€μ–΄ client.emit()λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ λ©”μ‹œμ§€λ₯Ό 생성할 수 μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 이 경우 인터셉터λ₯Ό μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. μ‚¬μš©μžμ—κ²Œ μ‘λ‹΅ν•˜μ§€ μ•ŠμœΌλ €λ©΄ 아무 것도 λ°˜ν™˜ν•˜μ§€ λ§ˆμ‹­μ‹œμ˜€ (λ˜λŠ” "μ •μ˜λ˜μ§€ μ•Šμ€"κ³Ό 같이 "거짓"값을 λͺ…μ‹œμ μœΌλ‘œ λ°˜ν™˜).

이제 ν΄λΌμ΄μ–ΈνŠΈκ°€ λ‹€μŒκ³Ό 같은 λ°©μ‹μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό 보낼 λ•Œ

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

handleEvent()λ©”μ†Œλ“œκ°€ μ‹€ν–‰λ©λ‹ˆλ‹€. μœ„ ν•Έλ“€λŸ¬ λ‚΄μ—μ„œ μƒμ„±λœ λ©”μ‹œμ§€λ₯Ό λ“€μœΌλ €λ©΄ ν΄λΌμ΄μ–ΈνŠΈκ°€ ν•΄λ‹Ή 승인 λ¦¬μŠ€λ„ˆλ₯Ό μ²¨λΆ€ν•΄μ•Όν•©λ‹ˆλ‹€.

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

Multiple responses

μŠΉμΈμ€ ν•œλ²ˆλ§Œ λ°œμ†‘λ©λ‹ˆλ‹€. λ˜ν•œ κΈ°λ³Έ WebSockets κ΅¬ν˜„μ—μ„œλŠ” μ§€μ›λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 이 μ œν•œμ„ ν•΄κ²°ν•˜κΈ° μœ„ν•΄ 두 가지 μ†μ„±μœΌλ‘œ κ΅¬μ„±λœ 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. μƒμ„±λœ 이벀트의 이름인 event와 ν΄λΌμ΄μ–ΈνŠΈμ— 전달해야 ν•˜λŠ” dataμž…λ‹ˆλ‹€.

@@filename(events.gateway)
@SubscribeMessage('events')
handleEvent(client: Client, data: unknown): WsResponse<unknown> {
  const event = 'events';
  return { event, data };
}
@@switch
@SubscribeMessage('events')
handleEvent(client, data) {
  const event = 'events';
  return { event, data };
}

info 힌트 WsResponse μΈν„°νŽ˜μ΄μŠ€λŠ” @nestjs/websockets νŒ¨ν‚€μ§€μ—μ„œ κ°€μ Έμ˜΅λ‹ˆλ‹€.

λ“€μ–΄μ˜€λŠ” 응닡을 λ“€μœΌλ €λ©΄ ν΄λΌμ΄μ–ΈνŠΈκ°€ λ‹€λ₯Έ 이벀트 λ¦¬μŠ€λ„ˆλ₯Ό μ μš©ν•΄μ•Όν•©λ‹ˆλ‹€.

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

Asynchronous responses

각 λ©”μ‹œμ§€ ν•Έλ“€λŸ¬λŠ” 동기식 λ˜λŠ” 비동기식 (async) 일 수 μžˆμœΌλ―€λ‘œ Promiseλ₯Ό λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ Observable을 λ°˜ν™˜ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 즉, μ—¬λŸ¬ 값을 λ°˜ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€ (슀트림이 μ™„λ£Œ 될 λ•ŒκΉŒμ§€ 방좜 됨).

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

  return from(response).pipe(
    map(data => ({ event, data })),
  );
}
@@switch
@SubscribeMessage('events')
onEvent(client, data) {
  const event = 'events';
  const response = [1, 2, 3];

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

μœ„μ˜ λ©”μ‹œμ§€ μ²˜λ¦¬κΈ°λŠ” 3 번 (μˆœμ„œλŒ€λ‘œ responseλ°°μ—΄μ˜ 각 ν•­λͺ©κ³Ό ν•¨κ»˜) μ‘λ‹΅ν•©λ‹ˆλ‹€.

Lifecycle hooks

3 가지 μœ μš©ν•œ 수λͺ…μ£ΌκΈ° 후크가 μžˆμŠ΅λ‹ˆλ‹€. λͺ¨λ‘ ν•΄λ‹Ή μΈν„°νŽ˜μ΄μŠ€κ°€ 있으며 λ‹€μŒ ν‘œμ— μ„€λͺ…λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

OnGatewayInit

afterInit() λ©”μ†Œλ“œλ₯Ό κ°•μ œλ‘œ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 라이브러리 νŠΉμ • μ„œλ²„ μΈμŠ€ν„΄μŠ€λ₯Ό 인수둜 μ‚¬μš©ν•©λ‹ˆλ‹€. (ν•„μš”ν•œ 경우 λ‚˜λ¨Έμ§€λ₯Ό ν™•μ‚°μ‹œν‚΅λ‹ˆλ‹€).

OnGatewayConnection

handleConnection() λ©”μ†Œλ“œλ₯Ό κ°•μ œλ‘œ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 라이브러리 νŠΉμ • ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“ μΈμŠ€ν„΄μŠ€λ₯Ό 인수둜 μ‚¬μš©ν•©λ‹ˆλ‹€.

OnGatewayDisconnect

handleDisconnect() λ©”μ†Œλ“œλ₯Ό κ°•μ œλ‘œ κ΅¬ν˜„ν•©λ‹ˆλ‹€. 라이브러리 νŠΉμ • ν΄λΌμ΄μ–ΈνŠΈ μ†ŒμΌ“ μΈμŠ€ν„΄μŠ€λ₯Ό 인수둜 μ‚¬μš©ν•©λ‹ˆλ‹€.

info 힌트 각 라이프 사이클 μΈν„°νŽ˜μ΄μŠ€λŠ”@nestjs/websockets νŒ¨ν‚€μ§€μ—μ„œ κ³΅κ°œλ©λ‹ˆλ‹€.

Server

κ²½μš°μ— 따라 ν”Œλž«νΌ 별 κΈ°λ³Έ μ„œλ²„ μΈμŠ€ν„΄μŠ€μ— 직접 μ•‘μ„ΈμŠ€ ν•  수 μžˆμŠ΅λ‹ˆλ‹€. 이 객체에 λŒ€ν•œ μ°Έμ‘°λŠ” afterInit()λ©”μ†Œλ“œ (OnGatewayInit μΈν„°νŽ˜μ΄μŠ€)에 인수둜 μ „λ‹¬λ©λ‹ˆλ‹€. 두 번째 방법은 @WebSocketServer()λ°μ½”λ ˆμ΄ν„°λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

@WebSocketServer()
server: Server;

warning μ•Œλ¦Ό @WebSocketServer()λ°μ½”λ ˆμ΄ν„°λŠ” @nestjs/websockets νŒ¨ν‚€μ§€μ—μ„œ κ°€μ Έμ˜΅λ‹ˆλ‹€.

NestλŠ” μ‚¬μš©ν•  μ€€λΉ„κ°€ 되면 μ„œλ²„ μΈμŠ€ν„΄μŠ€λ₯Ό 이 속성에 μžλ™μœΌλ‘œ ν• λ‹Ήν•©λ‹ˆλ‹€.

Example

μ‹€μ œ μ‚¬λ‘€λŠ” μ—¬κΈ°μ—μ„œ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

Last updated

Was this helpful?