Способы передачи данных от сервера к клиенту в веб-приложениях

От AJAX до WebSockets: разбираем, как сервер передаёт данные клиенту, чтобы ваши веб‑приложения работали мгновенно и без сбоев.

Бесплатная консультация юриста

+7 (800) 302-87-29

Реклама jurik.ru

Дата публикации:


В современных веб‑приложениях взаимодействие клиента и сервера происходит через сетевые запросы. После того как сервер обработал запрос, необходимо доставить результат обратно в браузер (или другое клиентское приложение), где он будет обработан и отображён пользователю. В этой статье рассматриваются основные способы передачи данных от сервера к клиенту, их особенности, преимущества и типичные сценарии использования.

Основные подходы

  1. AJAX / Fetch API – асинхронный запрос из JavaScript, позволяющий обновлять части страницы без полной перезагрузки.
  2. WebSocket – постоянное duplex‑соединение, при котором сервер может инициировать отправку данных клиенту в реальном времени.
  3. Server‑Sent Events (SSE) – односторонний поток от сервера к клиенту, удобный для live‑лент, уведомлений и т.п.
  4. Long Polling – эмуляция push‑уведомлений через обычные HTTP‑запросы, используемая там, где WebSocket недоступен.

HTTP‑ответ (REST/GraphQL)

Самый простой способ – клиент делает запрос GET, POST, PUT и т.д., а сервер формирует ответ с нужным статусом и телом.

Пример на Node.js (Express)

const express = require('express');
const app = express;

app.get('/api/users/:id', (req, res) => {
 const user = { id: req.params.id, name: 'Иван Иванов', age: 30 };
 res.json(user); // автоматически ставит Content-Type: application/json
});

app.listen(3000,  => console.log('Server running on port 3000'));

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

fetch('/api/users/42')
 .then(response => response.json)
 .then(data => {
 document.getElementById('userInfo').textContent = 
 `Имя: ${data.name}, Возраст: ${data.age}`;
 })
 .catch(err => console.error('Ошибка:', err));

Преимущества:

  • Простота реализации и отладки.
  • Широкая поддержка браузерами и серверными фреймворками.
  • Кешируемость (при правильных заголовках Cache-Control, ETag).

Недостатки:

  • Запрос‑ответ модели подразумевает задержку, равную RTT (round‑trip time).
  • Для частых обновлений требуется множество запросов.

AJAX / Fetch API

AJAX (Asynchronous JavaScript and XML) – техника, позволяющая выполнять запросы на сервер без перезагрузки страницы. Современный стандарт – fetch.

Пример с POST‑запросом

async function createComment(text) {
 const response = await fetch('/api/comments', {
 method: 'POST',
 headers: { 'Content-Type': 'application/json' },
 body: JSON.stringify({ text })
 });
 if (!response.ok) throw new Error(`HTTP ${response.status}`);
 const result = await response.json;
 return result; // объект, полученный от сервера
}

// Использование
createComment('Привет, мир!')
 .then(comment => {
 const li = document.createElement('li');
 li.textContent = comment.text;
 document.getElementById('commentsList').appendChild(li);
 }) .catch(console.error);

Преимущества:

  • Полный контроль над заголовками, методом и телом запроса.
  • Возможность обрабатывать ответы постепенно (например, через ReadableStream).

Недостатки:

  • Все ещё требует явного инициирования запроса со стороны клиента.
  • Нужно самостоятельно обрабатывать ошибки и таймауты.

WebSocket

WebSocket предоставляет постоянное двустороннее соединение через один TCP‑порт. После установления handshake клиент и сервер могут посылать друг другу сообщения в любое время.

Сервер (Node.js + ws)

const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', ws => {
 console.log('Клиент подключен');

 // При получении сообщения от клиента
 ws.on('message', message => {
 const data = JSON.parse(message);
 // Обработка... предположим, что нужно вернуть результат вычисления
 const result = { expr: data.expr, value: eval(data.expr) };
 ws.send(JSON.stringify(result));
 });

 ws.on('close',  => console.log('Клиент отключен'));
});

Клиент

const socket = new WebSocket('ws://localhost:8080');

socket.addEventListener('open',  => {
 socket.send(JSON.stringify({ expr: '2 + 2 * 3' }));
});

socket.addEventListener('message', event => {
 const data = JSON.parse(event.data);
 document.getElementById('result').textContent = 
 `${data.expr} = ${data.value}`;
});

socket.addEventListener('error', err => console.error('WebSocket error:', err));

Преимущества:

  • Минимальная задержка после установления соединения.
  • Сервер может инициировать отправку данных (push).
  • Эффективно для высокочастотного обмена (игры, чаты, биржевые котировки).

Недостатки:

  • Более сложная обработка соединений (переподключения, heartbeat).
  • Требует поддержки со стороны сервера и иногда прокси/балансировщиков.
  • Не подходит для простых запросов‑ответов, где достаточно REST.

Server‑Sent Events (SSE)

SSE – односторонний поток от сервера к клиенту, основанный на HTTP. Клиент открывает соединение EventSource и получает события вида data: {...}

.

Сервер (Express)

app.get('/events', (req, res) => {
 res.setHeader('Content-Type', 'text/event-stream');
 res.setHeader('Cache-Control', 'no-cache');
 res.setHeader('Connection', 'keep-alive');
 res.flushHeaders;

 const interval = setInterval( => {
 const data = { timestamp: new Date.toISOString, value: Math.random };
 res.write(`data: ${JSON.stringify(data)}

`);
 }, 1000);
 req.on('close',  => {
 clearInterval(interval);
 res.end;
 });
});
const evtSource = new EventSource('/events');

evtSource.onmessage = event => {
 const data = JSON.parse(event.data); `

[${data.timestamp}] ${data.value.toFixed(3)}

`; }; evtSource.onerror = err => { console.error('SSE error:', err); evtSource.close; };

Преимущества:

  • Автоматическое восстановление соединения после обрыва.
  • Проще, чем WebSocket, если нужна только сервер‑→‑клиент передача.
  • Работает через обычный HTTP, поэтому легко проходит через прокси.

Недостатки:

  • Односторонний – клиент не может посылать данные серверу через тот же канал (нужен отдельный запрос).
  • Не поддерживается в IE/Edge старых версий.

Long Polling

Long Polling – техника, при которой клиент отправляет запрос, а сервер держит его открытым до появления новых данных или истечения таймаута; После получения ответа клиент немедленно отправляет новый запрос.

Пример серверной логики (pseudo‑code)

function handleLongPoll(req, res) {
 const timeout = setTimeout( => {
 res.json({ message: 'timeout' });
 }, 30000); // 30 сек

 // Предположим, есть очередь сообщений для пользователя

 userMessageQueue.on('message', msg => {
 clearTimeout(timeout);
 res.json({ message: msg });
 });
 req.on('close',  => {
 clearTimeout(timeout);
 userMessageQueue.removeListener('message', /* handler */);
 });
}

Клиент (Fetch с рекурсией)

function startLongPoll {
 fetch('/longpoll')
 .then(r => r.json)
 .then(data => {
 console.log('Получено:', data);
 // обработка данных
 startLongPoll; // сразу запускаем следующий запрос
 }) .catch(err => {
 console.error('Ошибка long polling:', err);
 setTimeout(startLongPoll, 5000); // повтор через 5 сек после ошибки
 });
}
startLongPoll;

Преимущества:

  • Работает даже там, где WebSocket и SSE блокируются.
  • Прост в реализации на стороне сервера (можно использовать обычные обработчики).

Недостатки:

  • Больше нагрузки на сервер из‑за множества открытых соединений.
  • Задержка зависит от интервала между запросами.
  • Сложнее гарантировать порядок доставки при падении соединения.

Выбор подхода

Критерий REST/AJAX WebSocket SSE Long Polling
Направление Запрос‑ответ Дуплекс Сервер→Клиент Запрос‑ответ (с удержанием)
Задержка Средняя (RTT) Низкая Низкая Средняя‑высокая
Сложность Низкая Средняя‑высокая Низкая Средняя
Поддержка браузеров Все Все современные Все современные (IE нет) Все
Когда использовать Обычные CRUD‑операции, редкие обновления Чат, онлайн‑игры, торги, совместное редактирование Live‑ленты, уведомления, мониторинг Среды без WebSocket/SSE, необходимость простого fallback

Возврат результата запроса с сервера на клиент – фундаментальная часть любой веб‑системы. Выбор конкретного механизма зависит от требований к задержке, объёму данных, направленности потока и ограничений инфраструктуры. Для большинства типичных приложений достаточно REST/JSON в сочетании с Fetch API. Когда нужна реальная времени двусторонняя связь – WebSocket становится оптимальным решением. Если достаточно односторонних обновлений от сервера, стоит рассмотреть SSE, а в случае ограничений – Long Polling.

Понимание особенностей каждого подхода позволяет построить надёжное, масштабируемое и удобное для пользователей приложение.


Статья подготовлена . Все примеры кода носят illustrative характер и могут требовать адаптации под конкретный стек технологий.