Узнайте, как создать API чата в реальном времени, используя возможности WebSockets с помощью NestJS.
NestJS — это популярная платформа для создания серверных приложений с помощью Node.js. Благодаря поддержке WebSockets NestJS хорошо подходит для разработки приложений для чата в реальном времени.
Итак, что такое WebSockets и как создать приложение для чата в реальном времени в NestJS?
Что такое веб-сокеты?
WebSockets — это протокол для постоянной двусторонней связи в режиме реального времени между клиентом и сервером.
В отличие от HTTP, где соединение закрывается после завершения цикла запроса между клиентом и сервером, соединение WebSocket остается открытым и не закрывается даже после того, как ответ был возвращен для запрос.
Изображение ниже представляет собой визуализацию того, как работает связь WebSocket между сервером и клиентом:
Чтобы установить двустороннюю связь, клиент отправляет на сервер запрос на установление связи WebSocket. Заголовки запроса содержат безопасный ключ WebSocket (
Sec-WebSocket-ключ), и Обновление: веб-сокет заголовок, который вместе с Подключение: Обновление Заголовок указывает серверу обновить протокол с HTTP до WebSocket и оставить соединение открытым. Узнавать о Веб-сокеты в JavaScript помогает лучше понять концепцию.Создание API чата в реальном времени с использованием модуля NestJS WebSocket
Node.js предоставляет две основные реализации WebSockets. Первый ws который реализует голые веб-сокеты. И второй socket.io, который предоставляет более высокоуровневые функции.
NestJS имеет модули для обоих socket.io и ws. В этой статье используется socket.io модуль для функций WebSocket примера приложения.
Код, используемый в этом проекте, доступен в Репозиторий GitHub. Рекомендуется клонировать его локально, чтобы лучше понять структуру каталогов и увидеть, как все коды взаимодействуют друг с другом.
Настройка и установка проекта
Откройте свой терминал и создайте новое приложение NestJS, используя гнездо новое команда (напр. гнездо нового чат-приложения). Команда создает новый каталог, содержащий файлы проекта. Теперь вы готовы начать процесс разработки.
Настройка подключения к MongoDB
Чтобы сохранить сообщения чата в приложении, вам нужна база данных. В этой статье используется база данных MongoDB для нашего приложения NestJS, и самый простой способ начать работу — это настроить кластер MongoDB в облаке и получите URL-адрес MongoDB. Скопируйте URL-адрес и сохраните его как MONGO_URI переменная в вашем .env файл.
Вам также понадобится Mongoose позже, когда вы будете делать запросы к MongoDB. Установите его, запустив npm установить мангуста в вашем терминале.
в источник папку, создайте файл с именем монго.config.ts и вставьте в него следующий код.
Импортировать { зарегистрироваться как } от'@nestjs/config';
/**
* Конфигурация подключения к базе данных Mongo
*/
экспортпо умолчанию зарегистрироваться как('mongodb', () => {
константа { MONGO_URI } = процесс.env; // из файла .env
возвращаться {
ури:`${МОНГО_URI}`,
};
});
Ваш проект main.ts файл должен выглядеть так:
Импортировать {Фабрика гнезд} от'@nestjs/ядро';
Импортировать { AppModule } от'./app.module';
Импортировать * как cookieParser от'cookie-парсер'
Импортировать шлем от'шлем'
Импортировать { Регистратор, ValidationPipe } от'@nestjs/общий';
Импортировать { setupSwagger } от'./утилиты/чванство';
Импортировать { Фильтр исключений Http } от'./фильтры/http-исключение.фильтр';асинхронныйфункцияначальная загрузка() {
константа приложение = Ждите NestFactory.create(AppModule, { кор: истинный });
приложение.enableCors({
источник: '*',
реквизиты для входа: истинный
})
app.use (cookieParser())
приложение.useGlobalPipes(
новый ValidationPipe({
белый список: истинный
})
)
константа регистратор = новый Регистратор('Основной')app.setGlobalPrefix('апи/v1')
app.useGlobalFilters(новый HttpExceptionFilter());setupSwagger (приложение)
app.use (шлем())Ждите app.listen(AppModule.port)
// регистрируем документы
константа baseUrl = AppModule.getBaseUrl (приложение)
константа URL = `http://${базовый URL}:${AppModule.port}`
logger.log(`Документация по API доступна по адресу ${URL}/docs`);
}
начальная загрузка();
Создание модуля чата
Чтобы начать работу с функцией чата в реальном времени, первым шагом будет установка пакетов NestJS WebSockets. Это можно сделать, выполнив следующую команду в терминале.
установка npm @nestjs/websockets @nestjs/platform-socket.io @types/socket.io
После установки пакетов вам необходимо сгенерировать модуль чатов, выполнив следующие команды
чаты модуля Nest g
чаты контроллера Nest G
сервисные чаты Nest G
После создания модуля следующим шагом будет создание соединения WebSockets в NestJS. Создать чат.gateway.ts файл внутри чаты папка, именно здесь реализован шлюз, который отправляет и получает сообщения.
Вставьте следующий код в чат.gateway.ts.
Импортировать {
тело сообщения,
ПодписатьсяСообщение,
WebSocketGateway,
веб-сокетсервер,
} от'@nestjs/вебсокеты';
Импортировать { сервер } от'сокет.ио';
@WebSocketGateway()
экспортсортЧатШлюз{
@Веб-сокетсервер()
сервер: Сервер;
// прослушивание событий send_message
@ПодписатьСообщение('Отправить сообщение')
listenForMessages(@MessageBody() сообщение: строка) {
этот.server.sockets.emit('получить_сообщение', сообщение);
}
}
Аутентификация подключенных пользователей
Аутентификация — неотъемлемая часть веб-приложений, и она ничем не отличается от приложения чата. Функция аутентификации клиентских подключений к сокету находится в чаты.service.ts как показано здесь:
@Инъекционный()
экспортсортЧатыСервис{
конструктор(частный authService: AuthService) {}асинхронный getUserFromSocket (сокет: сокет) {
позволять auth_token = socket.handshake.headers.authorization;
// получаем сам токен без "Bearer"
auth_token = auth_token.split(' ')[1];константа пользователь = этот.authService.getUserFromAuthenticationToken(
auth_token
);
если (!пользователь) {
бросатьновый Исключение(«Недействительные учетные данные».);
}
возвращаться пользователь;
}
}
жетусерфромсокет метод использует GetUserFromAuthenticationToken чтобы получить текущего пользователя, вошедшего в систему, из токена JWT, извлекая токен Bearer. GetUserFromAuthenticationToken функция реализована в auth.service.ts файл, как показано здесь:
публичный асинхронный getUserFromAuthenticationToken (токен: строка) {
константа полезная нагрузка: JwtPayload = этот.jwtService.verify (токен, {
секрет: этот.configService.получить('JWT_ACCESS_TOKEN_SECRET'),
});константа идентификатор пользователя = полезная нагрузка.sub
если (ID пользователя) {
возвращатьсяэтот.usersService.findById (идентификатор пользователя);
}
}
Текущий сокет передается в качестве параметра жетусерфромсокет когда дескриптор соединения метод ЧатШлюз реализует OnGatewayConnection интерфейс. Это позволяет получать сообщения и информацию о подключенном в данный момент пользователе.
Код ниже демонстрирует это:
// чат.шлюз.ts
@WebSocketGateway()
экспортсортЧатШлюзреализуетOnGatewayConnection{
@Веб-сокетсервер()
сервер: Сервер;конструктор(приватные чатыService: ChatsService) {}
асинхронный handleConnection (сокет: сокет) {
Ждитеэтот.chatsService.getUserFromSocket (сокет)
}@ПодписатьСообщение('Отправить сообщение')
асинхронный listenForMessages(@MessageBody() сообщение: строка, @ConnectedSocket() сокет: Socket) {
константа пользователь = Ждитеэтот.chatsService.getUserFromSocket (сокет)
этот.server.sockets.emit('получить_сообщение', {
сообщение,
пользователь
});
}
}
Вы можете сослаться на файлы, задействованные в системе аутентификации выше, в Репозиторий GitHub чтобы увидеть полные коды (включая импорт), для лучшего понимания реализации.
Сохранение чатов в базе данных
Чтобы пользователи могли видеть свою историю сообщений, вам нужна схема для хранения сообщений. Создайте новый файл с именем message.schema.ts и вставьте в него приведенный ниже код (не забудьте импортировать схема пользователя или проверьте репозиторий для одного).
Импортировать { Пользователь } от'./../пользователи/схемы/пользователь.схема';
Импортировать { Опора, схема, фабрика схем} от"@nestjs/мангуст";
Импортировать мангуст, {Документ} от"мангуста";экспорт введите MessageDocument = Сообщение и Документ;
@Схема({
вJSON: {
геттеры: истинный,
виртуалы: истинный,
},
временные метки: истинный,
})
экспортсортСообщение{
@Prop({ необходимый: истинный, уникальный: истинный })
сообщение: строка@Prop({ тип: мангуст. Схема. Типы. идентификатор объекта, ссылка: 'Пользователь' })
пользователь: пользователь
}константа MessageSchema = SchemaFactory.createForClass (Сообщение)
экспорт {Схема сообщения};
Ниже приведена реализация сервисов для создания нового сообщения и получения всех сообщений в чаты.service.ts.
Импортировать { Сообщение, Документ-Сообщение } от'./сообщение.схема';
Импортировать { Разъем } от'сокет.ио';
Импортировать { Служба авторизации } от'./../авторизация/авторизация.сервис';
Импортировать { Инъекционный } от'@nestjs/общий';
Импортировать {ВсИсключение} от'@nestjs/вебсокеты';
Импортировать {ИнжектМодель} от'@nestjs/мангуст';
Импортировать {Модель} от'мангуста';
Импортировать { СообщениеDto } от'./dto/сообщение.dto';
@Инъекционный()
экспортсортЧатыСервис{
конструктор(private authService: AuthService, @InjectModel (Message.name) private messageModel: Model) {}
...
асинхронный createMessage (сообщение: MessageDto, ID пользователя: нить) {
константа новое сообщение = новыйэтот.messageModel({...сообщение, идентификатор пользователя})
Ждите новое сообщение.save
возвращаться новое сообщение
}
асинхронный получитьвсе сообщения () {
возвращатьсяэтот.messageModel.find().populate('пользователь')
}
}
СообщениеDto реализуется в сообщение.dto.ts файл в дто папка в чаты каталог. Вы также можете найти его в репозитории.
Вам необходимо добавить сообщение модель и схему в список импорта в чаты.модуль.тс.
Импортировать { Сообщение, схема сообщения } от'./сообщение.схема';
Импортировать {Модуль} от'@nestjs/общий';
Импортировать {Шлюз чата} от'./chats.шлюз';
Импортировать { Служба чатов } от'./chats.service';
Импортировать {Модуль мангуста} от'@nestjs/мангуст';
@Модуль({
импортирует: [MongooseModule.forFeature([
{ имя: Имя.сообщения, схема: Схема сообщения }
])],
контроллеры: [],
провайдеры: [ChatsService, ChatGateway]
})
экспортсортЧатыМодуль{}
Наконец, get_all_messages обработчик событий добавлен в ЧатШлюз класс в чат.gateway.ts как показано в следующем коде:
// импорт...
@WebSocketGateway()
экспортсортЧатШлюзреализуетOnGatewayConnection{
...@ПодписатьСообщение('get_all_messages')
асинхронный getAllMessages(@ConnectedSocket() сокет: сокет) {Ждитеэтот.chatsService.getUserFromSocket (сокет)
константа сообщения = Ждитеэтот.chatsService.getAllMessages()этот.server.sockets.emit('получить_сообщение', Сообщения);
возвращаться Сообщения
}
}
Когда подключенный клиент (пользователь) выдает get_all_messages событие, все их сообщения будут извлечены, и когда они испустят Отправить сообщение, сообщение создается и сохраняется в базе данных, а затем отправляется всем другим подключенным клиентам.
Выполнив все вышеперечисленные шаги, вы можете запустить свое приложение, используя запуск запуска npm: devи протестируйте его с помощью клиента WebSocket, такого как Postman.
Создание приложений реального времени с помощью NestJS
Хотя существуют и другие технологии для создания систем реального времени, веб-сокеты очень популярны и во многих случаях просты в реализации, и они являются лучшим вариантом для чат-приложений.
Приложения реального времени не ограничиваются только чат-приложениями, другие примеры включают потоковое видео или приложения для вызовов и приложения для работы с погодой в реальном времени, а NestJS предоставляет отличные инструменты для создания Программы.