Научете как да създадете API за чат в реално време, използвайки силата на WebSockets с помощта на NestJS.
NestJS е популярна рамка за изграждане на сървърни приложения с Node.js. Със своята поддръжка за WebSockets, NestJS е много подходящ за разработване на приложения за чат в реално време.
И така, какво представляват WebSockets и как можете да създадете приложение за чат в реално време в NestJS?
Какво представляват WebSockets?
WebSockets са протокол за постоянна двупосочна комуникация в реално време между клиент и сървър.
За разлика от HTTP, където връзката се затваря, когато цикълът на заявка е завършен между клиента и сървъра, връзка с WebSocket се поддържа отворена и не се затваря дори след връщане на отговор за a искане.
Изображението по-долу е визуализация на това как работи WebSocket комуникация между сървър и клиент:
За да установи двупосочна комуникация, клиентът изпраща WebSocket заявка за ръкостискане към сървъра. Заглавките на заявката съдържат защитен WebSocket ключ (Sec-WebSocket-Key
) и ан Надграждане: WebSocket заглавка, която заедно с Връзка: Надграждане header казва на сървъра да надстрои протокола от HTTP до WebSocket и да поддържа връзката отворена. Научаване за WebSockets в JavaScript помага да се разбере още по-добре концепцията.Изграждане на API за чат в реално време с помощта на модула NestJS WebSocket
Node.js предоставя две основни реализации на WebSockets. Първият е ws който имплементира голи WebSockets. И второто е socket.io, който предоставя функции на по-високо ниво.
NestJS има модули и за двете socket.io и ws. Тази статия използва socket.io модул за WebSocket функциите на примерното приложение.
Кодът, използван в този проект, е наличен в a GitHub хранилище. Препоръчително е да го клонирате локално, за да разберете по-добре структурата на директорията и да видите как всички кодове взаимодействат помежду си.
Настройка и инсталиране на проекта
Отворете вашия терминал и генерирайте ново приложение NestJS, като използвате гнездо ново команда (напр. nest ново приложение за чат). Командата генерира нова директория, която съдържа файловете на проекта. Сега сте готови да започнете процеса на разработка.
Настройте MongoDB връзка
За да запазите чат съобщенията в приложението, ви е необходима база данни. Тази статия използва базата данни MongoDB за нашето приложение NestJS, а най-лесният начин да започнете да бягате е да настройте MongoDB клъстер в облака и вземете своя MongoDB URL адрес. Копирайте URL адреса и го запазете като MONGO_URI променлива във вашия .env файл.
Също така ще имате нужда от Mongoose по-късно, когато правите заявки към MongoDB. Инсталирайте го, като стартирате npm инсталирайте mongoose във вашия терминал.
В src папка, създайте файл, наречен mongo.config.ts и поставете следния код в него.
импортиране { registerAs } от„@nestjs/config“;
/**
* Конфигурация за връзка с базата данни на Mongo
*/
износпо подразбиране registerAs("mongodb", () => {
конст {MONGO_URI} = process.env; // от .env файл
връщане {
uri:`${MONGO_URI}`,
};
});
Вашият проект main.ts файлът трябва да изглежда така:
импортиране { NestFactory } от'@nestjs/core';
импортиране { AppModule } от'./app.module';
импортиране * като cookieParser от"cookie-parser"
импортиране каска от"шлем"
импортиране {Регистратор, ValidationPipe} от„@nestjs/common“;
импортиране { setupSwagger } от'./utils/swagger';
импортиране {HttpExceptionFilter} от'./filters/http-exception.filter';асинхроненфункцияначално зареждане() {
конст приложение = изчакайте NestFactory.create (AppModule, { корс: вярно });
app.enableCors({
произход: '*',
акредитивни писма: вярно
})
app.use (cookieParser())
app.useGlobalPipes(
нов ValidationPipe({
бял списък: вярно
})
)
конст дървосекач = нов регистратор ("Главен")app.setGlobalPrefix("api/v1")
app.useGlobalFilters(нов HttpExceptionFilter());setupSwagger (приложение)
app.use (шлем())изчакайте app.listen (AppModule.port)
// регистрирайте документи
конст baseUrl = AppModule.getBaseUrl (приложение)
конст url = `http://${baseUrl}:${AppModule.port}`
logger.log(`Документация за API, налична на ${url}/docs`);
}
bootstrap();
Изграждане на модула за чат
За да започнете с функцията за чат в реално време, първата стъпка е да инсталирате пакетите NestJS WebSockets. Това може да стане чрез изпълнение на следната команда в терминала.
npm инсталирайте @nestjs/websockets @nestjs/platform-socket.io @types/socket.io
След като инсталирате пакетите, трябва да генерирате модула за чатове, като изпълните следните команди
чатове на модул nest g
чатове на контролера nest g
чатове на услугата nest g
След като приключите с генерирането на модула, следващата стъпка е да създадете WebSockets връзка в NestJS. Създавам chat.gateway.ts файл вътре в чатове папка, тук е внедрен шлюзът, който изпраща и получава съобщения.
Поставете следния код в chat.gateway.ts.
импортиране {
MessageBody,
Абониране Съобщение,
WebSocketGateway,
WebSocketServer,
} от'@nestjs/websockets';
импортиране { сървър } от'socket.io';
@WebSocketGateway()
износкласChatGateway{
@WebSocketServer()
сървър: сървър;
// слушане за събития send_message
@SubscribeMessage('изпрати съобщение')
listenForMessages(@MessageBody() съобщение: низ) {
това.server.sockets.emit('receive_message', съобщение);
}
}
Удостоверяване на свързаните потребители
Удостоверяването е съществена част от уеб приложенията и не е по-различно за приложението за чат. Функцията за удостоверяване на клиентските връзки към сокета се намира в chats.service.ts както е показано тук:
@Injectable()
износкласChatsService{
конструктор(private authService: AuthService) {}асинхронен getUserFromSocket (гнездо: гнездо) {
позволявам auth_token = socket.handshake.headers.authorization;
// вземете самия токен без "Носител"
auth_token = auth_token.split(' ')[1];конст потребител = това.authService.getUserFromAuthenticationToken(
auth_token
);
ако (!потребител) {
хвърлямнов WsException('Невалидни идентификационни данни.');
}
връщане потребител;
}
}
The getUserFromSocket използва метод getUserFromAuthenticationToken за да получите текущо влезлия потребител от JWT токена чрез извличане на токена на носителя. The getUserFromAuthenticationToken функцията е реализирана в auth.service.ts файл, както е показано тук:
публичен асинхронен getUserFromAuthenticationToken (токен: низ) {
конст полезен товар: JwtPayload = това.jwtService.verify (токен, {
тайна: това.configService.get(„JWT_ACCESS_TOKEN_SECRET“),
});конст userId = payload.sub
ако (userId) {
връщанетова.usersService.findById (userId);
}
}
Текущият сокет се предава като параметър към getUserFromSocket когато handleConnection метод на ChatGateway прилага на OnGatewayConnection интерфейс. Това прави възможно получаването на съобщения и информация за текущия свързан потребител.
Кодът по-долу демонстрира това:
// chat.gateway.ts
@WebSocketGateway()
износкласChatGatewayинструментиOnGatewayConnection{
@WebSocketServer()
сървър: сървър;конструктор(частни chatsService: ChatsService) {}
асинхронен handleConnection (сокет: гнездо) {
изчакайтетова.chatsService.getUserFromSocket (сокет)
}@SubscribeMessage('изпрати съобщение')
асинхронен listenForMessages(@MessageBody() съобщение: низ, @ConnectedSocket() гнездо: гнездо) {
конст потребител = изчакайтетова.chatsService.getUserFromSocket (сокет)
това.server.sockets.emit('receive_message', {
съобщение,
потребител
});
}
}
Можете да посочите файловете, включени в системата за удостоверяване по-горе в GitHub хранилище за да видите пълните кодове (включително импортирани), за по-добро разбиране на изпълнението.
Постоянни чатове към база данни
За да могат потребителите да виждат своята хронология на съобщенията, ви е необходима схема за съхраняване на съобщения. Създайте нов файл, наречен message.schema.ts и поставете кода по-долу в него (не забравяйте да импортирате вашия потребителска схема или разгледайте хранилището за такъв).
импортиране { потребител } от'./../users/schemas/user.schema';
импортиране { Prop, Schema, SchemaFactory } от"@nestjs/mongoose";
импортиране мангуста, {Документ} от"мангуста";износ тип MessageDocument = Съобщение и документ;
@Schema({
toJSON: {
получатели: вярно,
виртуални: вярно,
},
клеймото за време: вярно,
})
износкласСъобщение{
@Prop({ изисква се: вярно, единствен по рода си: вярно })
съобщение: низ@Prop({ Тип: мангуста. Схема. Видове. ObjectId, реф: "Потребител" })
потребител: потребител
}конст MessageSchema = SchemaFactory.createForClass (Съобщение)
износ { MessageSchema };
По-долу е изпълнение на услуги за създаване на ново съобщение и получаване на всички съобщения chats.service.ts.
импортиране { Съобщение, MessageDocument } от'./message.schema';
импортиране { Socket } от'socket.io';
импортиране { AuthService } от'./../auth/auth.service';
импортиране { Инжекционен } от„@nestjs/common“;
импортиране {WsException} от'@nestjs/websockets';
импортиране { InjectModel } от„@nestjs/mongoose“;
импортиране { Модел } от"мангуста";
импортиране { MessageDto } от'./dto/message.dto';
@Injectable()
износкласChatsService{
конструктор(private authService: AuthService, @InjectModel (Message.name) лично съобщениеModel: Модел) {}
...
асинхронен createMessage (съобщение: MessageDto, userId: низ) {
конст ново съобщение = новтова.messageModel({...съобщение, потребителско име})
изчакайте newMessage.save
връщане ново съобщение
}
асинхронен getAllMessages() {
връщанетова.messageModel.find().populate("потребител")
}
}
The MessageDto се изпълнява в a съобщение.dto.ts файл в dto папка в чатове указател. Можете също да го намерите в хранилището.
Трябва да добавите съобщение модел и схема към списъка за импортиране в chats.module.ts.
импортиране { Съобщение, MessageSchema } от'./message.schema';
импортиране { Модул } от„@nestjs/common“;
импортиране { ChatGateway } от'./chats.gateway';
импортиране { ChatsService } от'./chats.service';
импортиране { MongooseModule } от„@nestjs/mongoose“;
@Module({
импортира: [MongooseModule.forFeature([
{ име: Message.name, схема: Схема на съобщението }
])],
контролери: [],
доставчици: [ChatsService, ChatGateway]
})
износкласChatsModule{}
И накрая, на get_all_messages манипулаторът на събития се добавя към ChatGateway клас в chat.gateway.ts както се вижда в следния код:
// импортира...
@WebSocketGateway()
износкласChatGatewayинструментиOnGatewayConnection{
...@SubscribeMessage('get_all_messages')
асинхронен getAllMessages(@ConnectedSocket() socket: Socket) {изчакайтетова.chatsService.getUserFromSocket (сокет)
конст съобщения = изчакайтетова.chatsService.getAllMessages()това.server.sockets.emit('receive_message', съобщения);
връщане съобщения
}
}
Когато свързан клиент (потребител) излъчва get_all_messages събитие, всички техни съобщения ще бъдат извлечени и когато излъчат изпрати съобщение, съобщение се създава и съхранява в базата данни и след това се изпраща до всички други свързани клиенти.
След като приключите с всички горепосочени стъпки, можете да стартирате приложението си с помощта на npm стартиране стартиране: devи го тествайте с WebSocket клиент като Postman.
Изграждане на приложения в реално време с NestJS
Въпреки че има други технологии за изграждане на системи в реално време, WebSockets са много популярни и лесни за внедряване в много случаи и са най-добрият вариант за чат приложения.
Приложенията в реално време не са ограничени само до приложения за чат, други примери включват поточно видео или приложения за обаждания и приложения за времето на живо, а NestJS предоставя страхотни инструменти за изграждане в реално време приложения.