\n \n \n `);\n});\n\n// Клиент\nwindow.onMessage = function(data) {\n console.log(\"Сообщение:\", data.text);\n};\n\nconst iframe = document.createElement(\"iframe\");\niframe.src = \"/api/iframe-stream\";\niframe.style.display = \"none\";\ndocument.body.appendChild(iframe);\n```\n\n### Сравнение техник\n\n| Техника | Real-time | Двусторонняя | Простота | Нагрузка |\n|---------|-----------|-------------|----------|----------|\n| Polling | Плохо | Да | Очень | Высокая |\n| Long Polling | Хорошо | Да | Средняя | Средняя |\n| SSE | Отлично | Нет (only server->client) | Средняя | Низкая |\n| WebSocket | Отлично | Да | Сложно | Низкая |\n\n### Практический пример: Чат через Long Polling\n\n```javascript\nclass ChatClient {\n constructor(userId, serverUrl = \"/api/chat\") {\n this.userId = userId;\n this.serverUrl = serverUrl;\n this.isRunning = false;\n }\n\n async start() {\n this.isRunning = true;\n while (this.isRunning) {\n try {\n const response = await fetch(\n `${this.serverUrl}/messages?userId=${this.userId}&lastId=0`,\n { timeout: 30000 } // 30 сек таймаут\n );\n const data = await response.json();\n \n if (data.messages) {\n data.messages.forEach(msg => this.displayMessage(msg));\n }\n } catch (error) {\n console.error(\"Chat error:\", error);\n await new Promise(r => setTimeout(r, 2000)); // Reconnect delay\n }\n }\n }\n\n async sendMessage(text) {\n await fetch(`${this.serverUrl}/send`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n userId: this.userId,\n text: text,\n timestamp: Date.now()\n })\n });\n }\n\n stop() {\n this.isRunning = false;\n }\n\n displayMessage(message) {\n console.log(`${message.user}: ${message.text}`);\n }\n}\n```\n\n### Вывод\n\n**Для имитации WebSocket на HTTP используйте:**\n\n1. **Long Polling** — когда нужна двусторонняя real-time и простота\n2. **SSE** — когда нужны обновления только от сервера (notifications, live updates)\n3. **Polling** — когда Real-time не критичен\n4. **WebSocket** — когда нужна истинная двусторонняя real-time (лучший выбор)\n\nДля современных приложений предпочтительнее **WebSocket**, но Long Polling и SSE всё ещё полезны в специфических сценариях.","dateCreated":"2026-04-03T11:41:48.177220","upvoteCount":0,"author":{"@type":"Person","name":"claude-haiku-4.5"}}}}
← Назад к вопросам

Как имитировать работу Web Socket на HTTP?

1.8 Middle🔥 111 комментариев
#Браузер и сетевые технологии

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как имитировать работу Web Socket на HTTP

Различия WebSocket и HTTP

WebSocket:

  • Двусторонняя коммуникация (full-duplex)
  • Постоянное соединение
  • Низкие задержки
  • Меньше overhead

HTTP:

  • Запрос-ответ (half-duplex)
  • Соединение закрывается после ответа
  • Выше overhead (заголовки)
  • Требует polling или другого подхода для имитации real-time

Техника 1: Long Polling

Идея: Клиент отправляет запрос, сервер держит соединение открытым до появления новых данных.

// Клиент
class LongPollingClient {
  constructor(url) {
    this.url = url;
    this.isConnected = false;
  }

  connect() {
    this.isConnected = true;
    this.poll();
  }

  async poll() {
    while (this.isConnected) {
      try {
        const response = await fetch(this.url, {
          method: "GET",
          // Сервер может ждать до 30 сек, прежде чем ответить
        });

        if (!response.ok) break;

        const data = await response.json();
        
        if (data.messages.length > 0) {
          this.onMessage(data.messages);
        }
        
        // Сразу же отправляем новый запрос
      } catch (error) {
        this.onError(error);
        // Ждём перед переподключением
        await new Promise(resolve => setTimeout(resolve, 2000));
      }
    }
  }

  send(message) {
    fetch(this.url, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message })
    });
  }

  disconnect() {
    this.isConnected = false;
  }

  onMessage(messages) {
    console.log("Новые сообщения:", messages);
  }

  onError(error) {
    console.error("Ошибка Long Polling:", error);
  }
}

// Использование
const client = new LongPollingClient("/api/messages");
client.connect();

Сервер (Node.js/Express):

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

// Queue сообщений для каждого клиента
const clientQueues = new Map();

app.get("/api/messages", async (req, res) => {
  const clientId = req.query.clientId || Date.now();
  
  if (!clientQueues.has(clientId)) {
    clientQueues.set(clientId, []);
  }

  const queue = clientQueues.get(clientId);

  // Если есть сообщения — ответь сразу
  if (queue.length > 0) {
    return res.json({ messages: queue.splice(0) });
  }

  // Иначе ждём до 30 сек
  const timeout = setTimeout(() => {
    res.json({ messages: [] });
  }, 30000);

  // Когда придёт новое сообщение, отправим ответ
  const checkInterval = setInterval(() => {
    if (queue.length > 0) {
      clearTimeout(timeout);
      clearInterval(checkInterval);
      res.json({ messages: queue.splice(0) });
    }
  }, 500);
});

app.post("/api/messages", express.json(), (req, res) => {
  const { message } = req.body;
  
  // Разошли всем клиентам
  for (let [clientId, queue] of clientQueues) {
    queue.push(message);
  }

  res.json({ ok: true });
});

Плюсы:

  • Работает через обычный HTTP
  • Не требует WebSocket поддержки
  • Почти как real-time

Минусы:

  • Больше запросов
  • Выше latency
  • Больше нагрузка на сервер

Техника 2: Server-Sent Events (SSE)

Идея: Сервер отправляет события клиенту через HTTP, соединение остаётся открытым.

// Клиент
class SSEClient {
  constructor(url) {
    this.url = url;
    this.eventSource = null;
  }

  connect() {
    this.eventSource = new EventSource(this.url);

    this.eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      this.onMessage(data);
    };

    this.eventSource.onerror = (error) => {
      this.onError(error);
      // EventSource автоматически переподключается
    };
  }

  disconnect() {
    if (this.eventSource) {
      this.eventSource.close();
    }
  }

  onMessage(data) {
    console.log("Сообщение от сервера:", data);
  }

  onError(error) {
    console.error("SSE ошибка:", error);
  }
}

// Использование
const client = new SSEClient("/api/events");
client.connect();

Сервер (Node.js/Express):

app.get("/api/events", (req, res) => {
  // Устанавливаем заголовки для SSE
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");
  res.setHeader("Access-Control-Allow-Origin", "*");

  // Отправляем события
  const sendEvent = (data) => {
    res.write(`data: ${JSON.stringify(data)}\n\n`);
  };

  // Каждую секунду отправляем новое сообщение
  const interval = setInterval(() => {
    sendEvent({ message: "Привет!", timestamp: Date.now() });
  }, 1000);

  // Очищаем при отключении клиента
  req.on("close", () => {
    clearInterval(interval);
    res.end();
  });
});

Плюсы:

  • Одностороннее real-time (сервер -> клиент)
  • Автоматическое переподключение
  • Меньше overhead чем Long Polling

Минусы:

  • Только сервер -> клиент (нет двусторонней связи)
  • Работает только в HTTPS в проде

Техника 3: Polling

Самый простой вариант — клиент периодически запрашивает обновления.

class PollingClient {
  constructor(url, interval = 2000) {
    this.url = url;
    this.interval = interval;
    this.pollInterval = null;
  }

  start() {
    this.pollInterval = setInterval(() => {
      fetch(this.url)
        .then(res => res.json())
        .then(data => this.onMessage(data))
        .catch(error => this.onError(error));
    }, this.interval);
  }

  stop() {
    clearInterval(this.pollInterval);
  }

  onMessage(data) {
    console.log("Получены данные:", data);
  }

  onError(error) {
    console.error("Ошибка polling:", error);
  }
}

// Использование
const client = new PollingClient("/api/updates", 5000); // Каждые 5 сек
client.start();

Плюсы:

  • Очень просто
  • Работает везде

Минусы:

  • Много лишних запросов
  • Высокое latency
  • Высокая нагрузка на сервер

Техника 4: Iframe + Hidden Form

Legacy подход — используется редко, но исторически первый способ.

// Сервер отправляет JavaScript код, который вызывает колбэк
app.get("/api/iframe-stream", (req, res) => {
  res.setHeader("Content-Type", "text/html");
  
  res.write(`
    <html>
      <body>
        <script>
          parent.onMessage({ text: "Привет от сервера" });
          parent.onMessage({ text: "И ещё сообщение" });
        </script>
      </body>
    </html>
  `);
});

// Клиент
window.onMessage = function(data) {
  console.log("Сообщение:", data.text);
};

const iframe = document.createElement("iframe");
iframe.src = "/api/iframe-stream";
iframe.style.display = "none";
document.body.appendChild(iframe);

Сравнение техник

ТехникаReal-timeДвусторонняяПростотаНагрузка
PollingПлохоДаОченьВысокая
Long PollingХорошоДаСредняяСредняя
SSEОтличноНет (only server->client)СредняяНизкая
WebSocketОтличноДаСложноНизкая

Практический пример: Чат через Long Polling

class ChatClient {
  constructor(userId, serverUrl = "/api/chat") {
    this.userId = userId;
    this.serverUrl = serverUrl;
    this.isRunning = false;
  }

  async start() {
    this.isRunning = true;
    while (this.isRunning) {
      try {
        const response = await fetch(
          `${this.serverUrl}/messages?userId=${this.userId}&lastId=0`,
          { timeout: 30000 } // 30 сек таймаут
        );
        const data = await response.json();
        
        if (data.messages) {
          data.messages.forEach(msg => this.displayMessage(msg));
        }
      } catch (error) {
        console.error("Chat error:", error);
        await new Promise(r => setTimeout(r, 2000)); // Reconnect delay
      }
    }
  }

  async sendMessage(text) {
    await fetch(`${this.serverUrl}/send`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        userId: this.userId,
        text: text,
        timestamp: Date.now()
      })
    });
  }

  stop() {
    this.isRunning = false;
  }

  displayMessage(message) {
    console.log(`${message.user}: ${message.text}`);
  }
}

Вывод

Для имитации WebSocket на HTTP используйте:

  1. Long Polling — когда нужна двусторонняя real-time и простота
  2. SSE — когда нужны обновления только от сервера (notifications, live updates)
  3. Polling — когда Real-time не критичен
  4. WebSocket — когда нужна истинная двусторонняя real-time (лучший выбор)

Для современных приложений предпочтительнее WebSocket, но Long Polling и SSE всё ещё полезны в специфических сценариях.