Часто при разработке тех или иных приложений возникает потребность поддерживать двустороннюю связь между клиентом и сервером, то есть не только подгружать некоторые данные по запросу клиента, но и уметь динамически их обновлять при изменениях на сервере.
Самый простой вариант реализации такого поведение - делать периодические запросы к серверу за новыми данными. Но, во-первых, это порождает кучу лишних запросов и излишнюю нагрузку на сервер, и, во-вторых, данные будут приходить с очевидной задержкой.
💡 Один из более оптимальных вариантов реализации - это использование Long Polling. Фактически, это поддержание соединения между клиентом и сервером посредством обыкновенного длинного http-запроса, который удерживается сервером, пока в нём не появятся новые данные или не пройдёт сетевой таймаут. При этом после успешного ответа, таймаута или ошибки клиент инициирует новый запрос и цикл повторяется.
Простой пример реализации API с использованием библиотеки Express:
const messagesQueue = [];
// Route для отправки сообщений на сервер
app.post('/send', express.json(), (req, res) => {
const { message } = req.body;
messagesQueue.push(message);
res.status(200).send('Message received');
});
// Route для long polling
app.get('/poll', (req, res) => {
function checkForMessages() {
if (messagesQueue.length > 0) {
const messages = messagesQueue;
messagesQueue = [];
res.json(messages);
} else {
// Проверяем сообщения каждые 500 мс
setTimeout(checkForMessages, 500);
}
}
checkForMessages();
});
Как результат, на клиентах обновления будут ловиться с помощью метода
/poll, а обновляться с помощью метода /send. Один из плюсов этого метода с точки зрения сервера в том, что для его поддержания не нужны какие-либо дополнительные настройки, так как используются обыкновенные http-запросы.🤔 Звучит просто и круто, а какие у этого всего есть недостатки?
1. Использование ресурсов сервера - каждый Long Polling запрос требует, чтобы сервер удерживал соединение в открытом состоянии, что потребляет ресурсы сервера. Это может стать проблемой при большом количестве клиентов.
2. Задержка ответа - существует задержка между моментом появления данных и их получением клиентом, поскольку сервер должен дождаться окончания заданного интервала или появления данных перед тем, как ответить на заявку.
3. Управление ошибками и таймаутами - требуется аккуратное управление ошибками и таймаутами, чтобы избежать утечки ресурсов и удерживания соединений открытыми без необходимости.
4. Масштабируемость - масштабирование приложений с использованием Long Polling может быть сложным, поскольку каждое удерживаемое соединение занимает серверные ресурсы.
5. Отсутствие симметричности отправки и приёма сообщений - Long Polling оптимизирован для сценариев, где клиент чаще получает данные, чем отправляет. Направленная связь в обратном направлении не так эффективна.
🪄 Чуть более сложный пример реализации для обыкновенного чата на основе Long Polling есть в нашем репозитории. А в Live Demo можно потрогать результат и пообщаться!
⚡️ Как можно заметить, у этого метода есть много недостатков. Ставьте реакции, если вам интересна эта тема, чтобы углубиться в более эффективные способы реализации двусторонней связи между клиентом и сервером, такие как WebSockets, Server-Sent Events и WebRTC.