WebSocket в Fresh

Fresh — это современный веб-фреймворк для JavaScript и Deno, который делает акцент на рендеринг на сервере, простоту маршрутизации и минимизацию клиентского JavaScript. Одной из возможностей, которые часто необходимы в динамических приложениях, является работа с WebSocket для организации двусторонней связи между клиентом и сервером в реальном времени.

Основы WebSocket

WebSocket представляет собой протокол, позволяющий устанавливать постоянное соединение между клиентом и сервером, в отличие от стандартного HTTP, который предполагает запрос-ответ. Это делает его идеальным для чат-приложений, игровых платформ, дашбордов с обновляемыми данными и других интерактивных сервисов.

Основные преимущества WebSocket:

  • Двусторонняя связь: сервер может отправлять данные клиенту без его запроса.
  • Снижение нагрузки: отсутствует необходимость в постоянных HTTP-запросах (polling).
  • Малый накладной трафик: данные передаются без лишних HTTP-заголовков.

Настройка WebSocket в Fresh

Fresh из коробки поддерживает работу с Deno, что позволяет использовать встроенный API Deno.upgradeWebSocket. Для организации WebSocket-соединения нужно создать обработчик запроса, который выполняет апгрейд соединения.

Пример базового обработчика:

import { HandlerContext } from "$fresh/server.ts";

export const handler = (req: Request, _ctx: HandlerContext) => {
  const { socket, response } = Deno.upgradeWebSocket(req);

  socket.ono pen = () => {
    console.log("Соединение установлено");
  };

  socket.onmess age = (event) => {
    console.log("Сообщение от клиента:", event.data);
    socket.send(`Эхо: ${event.data}`);
  };

  socket.oncl ose = () => {
    console.log("Соединение закрыто");
  };

  socket.oner ror = (err) => {
    console.error("Ошибка WebSocket:", err);
  };

  return response;
};

В этом примере сервер получает запрос, апгрейдит его до WebSocket и обрабатывает события открытия соединения, получения сообщений, ошибок и закрытия соединения.

Интеграция с маршрутизацией Fresh

Fresh использует файловую маршрутизацию. Чтобы создать WebSocket-эндпоинт, достаточно разместить файл обработчика в папке routes. Например, файл routes/ws.ts:

export const handler = (req: Request) => {
  const { socket, response } = Deno.upgradeWebSocket(req);

  socket.ono pen = () => socket.send("Добро пожаловать в WebSocket!");
  socket.onmess age = (event) => socket.send(`Вы отправили: ${event.data}`);
  
  return response;
};

При этом любой запрос на /ws будет автоматически направлен в этот обработчик.

Клиентская часть

Для подключения к WebSocket на клиенте используется стандартный объект WebSocket. В Fresh можно подключить его внутри компонента или напрямую через <script> в шаблоне.

Пример подключения:

<script>
  const socket = new WebSocket("ws://localhost:8000/ws");

  socket.ono pen = () => console.log("Соединение установлено");
  socket.onmess age = (event) => console.log("Сообщение с сервера:", event.data);
  socket.oncl ose = () => console.log("Соединение закрыто");
</script>

Ключевой момент — URL WebSocket должен соответствовать пути на сервере и использовать протокол ws:// или wss:// для защищённого соединения.

Продвинутые техники

1. Работа с несколькими клиентами. Для поддержки множества подключений обычно используется массив или Map сокетов:

const clients = new Set();

socket.ono pen = () => {
  clients.add(socket);
};

socket.oncl ose = () => {
  clients.delete(socket);
};

function broadcast(message) {
  for (const client of clients) {
    client.send(message);
  }
}

2. Протоколирование сообщений и авторизация. Перед отправкой сообщений можно проверять токены, идентификаторы пользователей и логировать действия, чтобы обеспечить безопасность и мониторинг соединений.

3. Интеграция с рендерингом Fresh. WebSocket легко интегрировать с компонентами Fresh: при поступлении данных сервер может обновлять состояние и отправлять только необходимые изменения клиенту. Это позволяет создавать высокоэффективные динамические страницы с минимальным использованием клиентского JavaScript.

Особенности и ограничения

  • Fresh ориентирован на рендеринг на сервере, поэтому клиентский WebSocket-код обычно ограничивается компонентами или скриптами на странице.
  • Для масштабирования WebSocket-соединений рекомендуется использовать отдельный сервер WebSocket или прокси, так как встроенный сервер Deno ограничен по количеству одновременных соединений.
  • Deno поддерживает только один апгрейд WebSocket на один запрос, что требует тщательного управления обработчиками.

WebSocket в Fresh позволяет создавать интерактивные, реального времени приложения, используя минимальный объём кода и сохраняя преимущества серверного рендеринга. Благодаря встроенной поддержке Deno и простой интеграции с маршрутизацией, можно быстро развернуть функциональные решения для чатов, дашбордов и других динамических сервисов.