WebSockets — real-time ilovalar
Muammodan boshlaylik
Chat ilovasi yozyapsiz. Foydalanuvchi A xabar yubordi — foydalanuvchi B darhol ko'rishi kerak.
Oddiy HTTP bilan bu ishlamaydi:
Foydalanuvchi B har 2 soniyada so'rashi kerak:
"Yangi xabar bormi?" → "Yo'q"
"Yangi xabar bormi?" → "Yo'q"
"Yangi xabar bormi?" → "Ha, mana"
Bu polling — server qayta-qayta so'raladi, resurs behuda sarflanadi. Xabar kelishi bilan emas, keyingi so'rovda ko'rinadi.
Real-time kerak: xabar kelsa — server o'zi mijozga yubora olsin.
WebSocket nima?
WebSocket — server va client orasida ikki tomonlama doimiy ulanish.
HTTP da har so'rovdan keyin ulanish yopiladi. WebSocket da — bir marta ulanasiz va ikkalasi ham istaganida xabar yuborishi mumkin.
HTTP:
Client ──► Server (so'rov)
Client ◄── Server (javob)
(ulanish yopildi)
WebSocket:
Client ◄──────────────────► Server
xabar yubor →
← xabar ol
yana yubor →
Telegram, WhatsApp, online o'yinlar — barchasi WebSocket ishlatadi.
Hayotiy o'xshatma
Tasavvur qiling: radio aloqasi. Politsiya xodimlari radiopriyomnik orqali bir-biri bilan gaplashadi. Biri gapirsa — hammasi eshitadi. Ikki tomonlama, doimiy ulanish. HTTP esa aksincha — har safar telefondan qo'ng'iroq qilib, javob kutib, ulanish yopiladi.
Nima uchun Gateway?
NestJS da WebSocket server Gateway deb ataladi — Controller ga o'xshaydi, lekin HTTP emas, socket eventlarini tinglaydi.
HTTP: @Controller → @Get/@Post → HTTP so'rov
Socket: @WebSocketGateway → @SubscribeMessage → socket event
O'rnatish
npm install @nestjs/websockets @nestjs/platform-socket.io socket.io
Fayl tuzilmasi
src/
chat/
chat.gateway.ts ← WebSocket server
chat.module.ts
Gateway yaratish
// chat/chat.gateway.ts
import {
WebSocketGateway,
WebSocketServer,
SubscribeMessage,
MessageBody,
} from '@nestjs/websockets';
import { Server } from 'socket.io';
@WebSocketGateway({ cors: { origin: '*' } })
export class ChatGateway {
@WebSocketServer()
server: Server; // ← barcha ulanganlar bilan ishlash uchun
// Client 'sendMessage' event yuborganda bu ishga tushadi
@SubscribeMessage('sendMessage')
handleMessage(@MessageBody() text: string) {
// Barcha ulanganlarga qaytarib yuborish
this.server.emit('newMessage', { text, time: new Date() });
}
}
Module ga qo'shish
// chat/chat.module.ts
import { Module } from '@nestjs/common';
import { ChatGateway } from './chat.gateway';
@Module({
providers: [ChatGateway],
})
export class ChatModule {}
AppModule ga ChatModule ni import qiling.
Xonalar (Rooms)
Chat da odatda xonalar bo'ladi — har bir xona alohida guruh. "Umumiy" xonadagilar faqat o'z xonalarini ko'radi.
import { ConnectedSocket, MessageBody, SubscribeMessage } from '@nestjs/websockets';
import { Socket } from 'socket.io';
@WebSocketGateway({ cors: { origin: '*' } })
export class ChatGateway {
@WebSocketServer()
server: Server;
// Xonaga qo'shilish
@SubscribeMessage('joinRoom')
joinRoom(@MessageBody() room: string, @ConnectedSocket() client: Socket) {
client.join(room); // ← client shu xonaga qo'shildi
}
// Faqat shu xona a'zolariga yuborish
@SubscribeMessage('sendMessage')
sendToRoom(
@MessageBody() data: { room: string; text: string },
@ConnectedSocket() client: Socket,
) {
this.server.to(data.room).emit('newMessage', {
text: data.text,
from: client.id,
});
}
}
Ulanish va uzilishni kuzatish
import { OnGatewayConnection, OnGatewayDisconnect } from '@nestjs/websockets';
@WebSocketGateway({ cors: { origin: '*' } })
export class ChatGateway implements OnGatewayConnection, OnGatewayDisconnect {
handleConnection(client: Socket) {
console.log(`Ulandi: ${client.id}`);
}
handleDisconnect(client: Socket) {
console.log(`Uzildi: ${client.id}`);
}
}
Frontend dan ulash
import { io } from 'socket.io-client';
const socket = io('http://localhost:3000');
// Xonaga kirish
socket.emit('joinRoom', 'general');
// Xabar yuborish
socket.emit('sendMessage', { room: 'general', text: 'Salom!' });
// Yangi xabarni qabul qilish
socket.on('newMessage', (data) => {
console.log(`${data.from}: ${data.text}`);
});
Tez-tez uchraydigan xatolar
1. CORS xatosi
Cross-Origin Request Blocked
Sababi: Gateway CORS sozlanmagan.
Yechim: @WebSocketGateway({ cors: { origin: 'http://yourfrontend.com' } })
2. Xabar kelmayapti
Sababi: socket.emit('sendMessage') va @SubscribeMessage('sendMessage') — nomlar mos kelmayapti.
Yechim: Ikki tomonda event nomi aynan bir xil bo'lsin, katta-kichik harf muhim.
3. Nginx da WebSocket ishlamayapti
Sababi: Nginx Upgrade headerni o'tkazmayapti.
Yechim: Nginx konfiguratsiyaga qo'shing:
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
Xulosa
- WebSocket — ikki tomonlama doimiy ulanish, HTTP emas
@WebSocketGateway()— WebSocket server yaratadi@SubscribeMessage('event')— shu nomdagi eventni tinglaydiserver.emit()— barcha ulanganlarga yuboradiserver.to(room).emit()— faqat xona a'zolariga yuboradi
Keyingi dars: 38-dars: Server-Sent Events — bir tomonlama real-time