WebSockets6 min read

Gatewaylar

Hujjatlarning boshqa joylarida muhokama qilingan ko'plab tushunchalar, masalan, dependency injection, dekoratorlar, exception filterlar, pipelar, guardlar va interceptorlar gateway

Hujjatlarning boshqa joylarida muhokama qilingan ko'plab tushunchalar, masalan, dependency injection, dekoratorlar, exception filterlar, pipelar, guardlar va interceptorlar gatewaylarga ham birdek qo'llanadi. Imkon qadar Nest implementatsiya tafsilotlarini abstraksiyalaydi, shuning uchun bir xil komponentlar HTTP asosidagi platformalar, WebSockets va Microservices bo'ylab ishlay oladi. Bu bo'lim WebSocketsga xos bo'lgan Nest jihatlarini qamrab oladi.

Nest'da gateway bu shunchaki @WebSocketGateway() dekoratori bilan belgilangan klass. Texnik jihatdan gatewaylar platforma-agnostik bo'lib, adapter yaratilgandan so'ng istalgan WebSockets kutubxonasi bilan mos keladi. Qutidan ikkita WS platformasi qo'llab-quvvatlanadi: socket.io va ws. Ehtiyojingizga mosini tanlashingiz mumkin. Shuningdek, ushbu guide bo'yicha o'zingizning adapteringizni ham yaratishingiz mumkin.

Hint

Gatewaylar providers sifatida qaralishi mumkin; bu ularning konstruktor orqali dependency inject qilishini anglatadi. Shuningdek, gatewaylarni boshqa klasslar (providerlar va controllerlar) ham inject qilishi mumkin.

O'rnatish

WebSockets asosidagi ilovalarni qurishni boshlash uchun avval kerakli paketni o'rnating:

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

Umumiy ko'rinish

Umuman olganda, har bir gateway HTTP server bilan bir xil portda tinglaydi, agar ilovangiz web ilova bo'lmasa yoki portni qo'lda o'zgartirmagan bo'lsangiz. Bu standart xatti-harakat @WebSocketGateway(80) dekoratoriga argument uzatish orqali o'zgartiriladi, bu yerda 80 tanlangan port raqami. Shuningdek, quyidagi konstruktsiya orqali gateway ishlatadigan namespace ni belgilashingiz mumkin:

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

Gatewaylar mavjud modulning providers massivida ko'rsatilmaguncha instansiyalanmaydi.

Quyida ko'rsatilgandek, @WebSocketGateway() dekoratorining ikkinchi argumenti bilan socket konstruktoriga qo'llab-quvvatlanadigan istalgan optionni uzatishingiz mumkin:

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

Gateway endi tinglayapti, ammo biz hali hech qanday kiruvchi xabarlarga obuna bo'lmadiq. Keling, events xabarlariga obuna bo'lib, foydalanuvchiga aynan shu ma'lumotni qaytaradigan handler yarataylik.

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(@MessageBody() data: string): string {
3  return data;
4}
Hint

@SubscribeMessage() va @MessageBody() dekoratorlari @nestjs/websockets paketidan import qilinadi.

Gateway yaratilgach, uni modulimizda ro'yxatdan o'tkazishimiz mumkin.

TypeScript
events.module
1import { Module } from '@nestjs/common';
2import { EventsGateway } from './events.gateway';
3
4@Module({
5  providers: [EventsGateway]
6})
7export class EventsModule {}

Shuningdek, dekoratorga property key uzatib, uni kiruvchi xabar body'sidan ajratib olishingiz mumkin:

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(@MessageBody('id') id: number): number {
3  // id === messageBody.id
4  return id;
5}

Agar dekoratorlardan foydalanishni xohlamasangiz, quyidagi kod funksional jihatdan ekvivalent:

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(client: Socket, data: string): string {
3  return data;
4}

Yuqoridagi misolda handleEvent() funksiyasi ikki argumentni qabul qiladi. Birinchisi platformaga xos socket instansiyasi, ikkinchisi esa mijozdan olingan ma'lumot. Biroq bu yondashuv tavsiya etilmaydi, chunki u har bir unit testda socket instansiyasini mock qilishni talab qiladi.

events xabari qabul qilingach, handler tarmoq orqali yuborilgan ma'lumotning o'zini qaytarib, acknowledgment yuboradi. Bundan tashqari, kutubxonaga xos yondashuv orqali xabarlar emit qilish ham mumkin, masalan, client.emit() metodidan foydalanish. Ulangan socket instansiyasiga kirish uchun @ConnectedSocket() dekoratoridan foydalaning.

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(
3  @MessageBody() data: string,
4  @ConnectedSocket() client: Socket,
5): string {
6  return data;
7}
Hint

@ConnectedSocket() dekoratori @nestjs/websockets paketidan import qilinadi.

Biroq, bu holatda interceptorlardan foydalana olmaysiz. Agar foydalanuvchiga javob qaytarishni xohlamasangiz, shunchaki return statementini tashlab ketishingiz mumkin (yoki aniq "falsy" qiymatni qaytarishingiz mumkin, masalan undefined).

Endi mijoz quyidagicha xabar emit qilganda:

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

handleEvent() metodi bajariladi. Yuqoridagi handler ichidan emit qilingan xabarlarni eshitish uchun mijoz mos acknowledgment listenerni ulashi kerak:

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

Message handlerdan qiymat qaytarish implicit ravishda acknowledgment yuborsa-da, murakkab ssenariylar ko'pincha acknowledgment callbackini bevosita boshqarishni talab qiladi.

@Ack() parametr dekoratori ack callback funksiyasini to'g'ridan-to'g'ri message handlerga inject qilish imkonini beradi. Dekoratorsiz bu callback metodning uchinchi argumenti sifatida uzatiladi.

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(
3  @MessageBody() data: string,
4  @Ack() ack: (response: { status: string; data: string }) => void,
5) {
6  ack({ status: 'received', data });
7}

Bir nechta javoblar

Acknowledgment faqat bir marta yuboriladi. Bundan tashqari, u native WebSockets implementatsiyasida qo'llab-quvvatlanmaydi. Bu cheklovni yechish uchun ikki propertydan iborat obyekt qaytarishingiz mumkin. event - emit qilinadigan hodisa nomi, data esa mijozga uzatilishi kerak bo'lgan ma'lumot.

TypeScript
events.gateway
1@SubscribeMessage('events')
2handleEvent(@MessageBody() data: unknown): WsResponse<unknown> {
3  const event = 'events';
4  return { event, data };
5}
Hint

WsResponse interfeysi @nestjs/websockets paketidan import qilinadi.

Warning

Agar data maydoni ClassSerializerInterceptorga tayanayotgan bo'lsa, WsResponseni implement qiladigan klass instansiyasini qaytarishingiz kerak, chunki u oddiy JavaScript obyekt javoblarini e'tiborsiz qoldiradi.

Kiruvchi javob(lar)ni eshitish uchun mijoz yana bir event listener ulashi kerak.

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

Asinxron javoblar

Message handlerlar sinxron yoki asinxron javob bera oladi. Shuning uchun async metodlar qo'llab-quvvatlanadi. Message handler Observable ham qaytarishi mumkin, bu holda stream tugaguncha natija qiymatlar emit qilinadi.

TypeScript
events.gateway
1@SubscribeMessage('events')
2onEvent(@MessageBody() data: unknown): Observable<WsResponse<number>> {
3  const event = 'events';
4  const response = [1, 2, 3];
5
6  return from(response).pipe(
7    map(data => ({ event, data })),
8  );
9}

Yuqoridagi misolda message handler 3 marta javob beradi (massivdagi har bir element bilan).

Lifecycle hooklar

3 ta foydali lifecycle hook mavjud. Ularning barchasi mos interfeyslarga ega va quyidagi jadvalda tasvirlangan:

OnGatewayInit afterInit() metodini implement qilishni majbur qiladi. Kutubxonaga xos server instansiyasini argument sifatida oladi (va kerak bo'lsa qolganlarini spread qiladi).
OnGatewayConnection handleConnection() metodini implement qilishni majbur qiladi. Kutubxonaga xos client socket instansiyasini argument sifatida oladi.
OnGatewayDisconnect handleDisconnect() metodini implement qilishni majbur qiladi. Kutubxonaga xos client socket instansiyasini argument sifatida oladi.
Hint

Har bir lifecycle interfeysi @nestjs/websockets paketidan taqdim etiladi.

Server va Namespace

Ba'zan native, platformaga xos server instansiyasiga bevosita kirishni xohlashingiz mumkin. Bu obyektga referensiya afterInit() metodiga (OnGatewayInit interfeysi) argument sifatida uzatiladi. Yana bir variant - @WebSocketServer() dekoratoridan foydalanish.

TypeScript
1@WebSocketServer()
2server: Server;

Shuningdek, quyidagicha namespace atributi orqali mos namespace'ni olishingiz mumkin:

TypeScript
1@WebSocketGateway({ namespace: 'my-namespace' })
2export class EventsGateway {
3  @WebSocketServer()
4  namespace: Namespace;
5}

@WebSocketServer() dekoratori @WebSocketGateway() dekoratori saqlagan metadata'ga tayangan holda server instansiyasini inject qiladi. Agar @WebSocketGateway() dekoratoriga namespace opsiyasini bersangiz, @WebSocketServer() dekoratori Server instansiyasi o'rniga Namespace instansiyasini qaytaradi.

Notice

@WebSocketServer() dekoratori @nestjs/websockets paketidan import qilinadi.

Nest server instansiyasini foydalanishga tayyor bo'lishi bilan avtomatik ravishda ushbu property'ga tayinlaydi.

Misol

Ishlaydigan misol here mavjud.