83ef0d5ab3d4610eef4392823abf73671a97a6ab
Чат с общей комнатой
Веб-приложение чата с одной общей комнатой на WebSocket. Поддерживает текстовые сообщения, отправку файлов и отображение изображений.
Сервер: Node.js + ws
Клиент: React + Vite
Прокси: nginx (production-сборка)
Быстрый запуск (разработка)
Сервер
cd server
npm install
npm start
Запускает WebSocket сервер на ws://localhost:8080.
Клиент
cd client
npm install
npx vite
Запускает dev-сервер на http://localhost:3000.
В режиме разработки клиент подключается напрямую к ws://localhost:8080.
Пользователи по умолчанию
| Логин | Пароль |
|---|---|
| alice | 123 |
| bob | 456 |
Production (Docker)
Сборка образа
docker build -t chat-app .
Запуск контейнера
docker run -d -p 80:80 chat-app
Открой http://localhost.
Как это работает
- nginx на порту 80 раздаёт статику React и проксирует WebSocket
- Путь
/→ статические файлы клиента (index.html, JS, CSS) - Путь
/ws→ прокси на Node.js WebSocket сервер (порт 8080 внутри контейнера) - nginx поддерживает Upgrade до WebSocket, таймаут соединения — 24 часа
- Максимальный размер загружаемых файлов через nginx — 50 МБ
- После остановки Node.js контейнер завершается (через
wait)
Переменные окружения
Сервер
| Переменная | По умолчанию | Описание |
|---|---|---|
PORT |
8080 |
Порт WebSocket сервера |
MAX_FILE_SIZE |
10485760 (10 МБ) |
Максимальный размер файла в байтах |
USERS_FILE |
users.json |
Путь к файлу с пользователями |
Пример:
$env:PORT=9090; $env:MAX_FILE_SIZE=2097152; node server.js
Клиент
| Переменная | По умолчанию (dev) | По умолчанию (production) | Описание |
|---|---|---|---|
VITE_WS_URL |
ws://localhost:8080 |
/ws |
URL WebSocket сервера |
Настройки хранятся в файлах:
client/.env.development— дляnpx vite(dev-режим)client/.env— дляvite build(production-сборка)
Протокол обмена
Аутентификация
Клиент → Сервер:
{ "type": "auth", "login": "alice", "password": "123" }
Сервер → Клиент:
{ "type": "auth_result", "success": true }
{ "type": "auth_result", "success": false, "reason": "Invalid login or password" }
Текстовое сообщение
Клиент → Сервер:
{ "type": "text", "text": "Привет!" }
Сервер → Все:
{ "type": "text", "from": "alice", "timestamp": 1717000000000, "text": "Привет!" }
Файл / изображение
Клиент → Сервер:
{
"type": "file",
"filename": "cat.png",
"mime": "image/png",
"data": "<base64>"
}
Сервер → Все (такая же структура, добавлены from и timestamp):
{
"type": "file",
"from": "alice",
"timestamp": 1717000000000,
"filename": "cat.png",
"mime": "image/png",
"data": "<base64>"
}
Системные сообщения
Сервер → Все:
{ "type": "system", "text": "alice joined the chat" }
Функциональность
- Текстовые сообщения — отображаются с логином отправителя и временем
- Файлы — любые типы, до 10 МБ (настраивается). Файлы передаются через base64 в JSON
- Изображения — автоматически определяются по MIME-типу (
image/*), рендерятся как<img>, клик открывает в новой вкладке - Не-изображения — отображаются как ссылка для скачивания с именем файла
- Уведомления на неактивной вкладке — звуковой сигнал (Web Audio API) и красная точка на favicon
- Системные сообщения — подключение / отключение участников
- Скролл — автоматический, кастомный тонкий скроллбар в теме приложения
Структура проекта
chat/
├── server/
│ ├── server.js # WebSocket сервер
│ ├── users.json # Хардкоженые логины/пароли
│ └── package.json
├── client/
│ ├── src/
│ │ ├── App.jsx # Корневой компонент
│ │ ├── App.css
│ │ ├── main.jsx # Точка входа
│ │ └── components/
│ │ ├── Login.jsx / .css
│ │ ├── Chat.jsx / .css
│ │ ├── MessageList.jsx
│ │ ├── Message.jsx / .css
│ │ └── MessageInput.jsx / .css
│ ├── .env # Production настройки
│ ├── .env.development # Dev настройки
│ ├── index.html
│ ├── vite.config.js
│ └── package.json
├── Dockerfile # Многостадийная сборка
├── docker-entrypoint.sh # Точка входа контейнера
├── nginx.conf # Конфигурация nginx
└── README.md
Languages
JavaScript
77.2%
CSS
18.8%
Dockerfile
1.9%
Shell
1.4%
HTML
0.7%