Веб-сокеты (Web Sockets) — это передовая технология, которая позволяет создавать интерактивное соединение между клиентом (браузером) и сервером для обмена сообщениями в режиме реального времени. Веб-сокеты, в отличие от HTTP, позволяют работать с двунаправленным потоком данных, что делает эту технологию совершенно уникальной. Давайте разберемся, как работает эта технология и чем она отличается от HTTP.
Как работает HTTP?
Вы наверняка знаете, что такое HTTP (или HTTPS), поскольку встречаетесь с этим протоколом каждый день в своём браузере. Браузер постоянно спрашивает у сервера, есть ли для него новые сообщения, и получает их.
Вы также можете знать, что HTTP позволяет использовать разные типы запросов, такие как POST, GET или PUT, каждый из которых имеет своё назначение.
Как работают веб-сокеты?
Веб-сокетам же для ответа не нужны ваши повторяющиеся запросы. Достаточно выполнить один запрос и ждать отклика. Вы можете просто слушать сервер, который будет отправлять вам сообщения по мере готовности.
Веб-сокеты можно использовать, если вы разрабатываете:
- приложения реального времени;
- чат-приложения;
- IoT-приложения;
- многопользовательские игры.
Когда следует избегать использования веб-сокетов?
Практически никогда. Единственный минус — это несовместимость с некоторыми браузерами, но уже 95 % браузеров поддерживают веб-сокеты.
В некоторых случаях веб-сокеты вам всё же не понадобятся. Если вы создаёте простую CMS, вам вряд ли пригодится функциональность в режиме реального времени. Также не стоит использовать веб-сокеты в REST API, поскольку вам хватит таких HTTP-запросов, как GET, POST, DELETE и PUT.
Практические примеры
В примерах ниже для клиента используется JavaScript, а для сервера — Node.js. Примеры очень просты и вряд ли пригодятся на практике, но зато позволят разобраться в сути.
Веб-сокеты
Клиент:
<!DOCTYPE html>
<html>
<head>
<title>Пример чата с веб-сокетом</title>
</head>
<body>
<script>
let ws = new WebSocket("ws://localhost:8080");
// выводим новые сообщения в консоль
ws.onmessage = ({data}) => {
console.log(data);
}
// отправляем сообщение
ws.onopen = () => ws.send('Text');
</script>
</body>
</html>
Сервер:
const WebSocket = require('ws');
// создаём новый websocket-сервер
const wss = new WebSocket.Server({
port: 8080
});
// отправляем клиентам, когда функция clientValidator возвращает true. this — это wss.
wss.broadcast = function(data, clientValidator = () => true) {
this.clients.forEach(client => {
if (clientValidator(client)) {
client.send(data);
}
});
}
wss.on("connection", ws => {
// событие будет вызвано, когда клиент отправит сообщение
ws.on('message', message => {
// отправляем сообщение всем, кроме автора
wss.broadcast(message, client => client !== ws);
});
});
Вот иллюстрация работы веб-сокетов:
Эквивалент в HTTP
Так как HTTP должен постоянно проверять канал на наличие новых сообщений, можно использовать «грязную» проверку (dirty check) — подход, при котором клиент с заданной периодичностью (допустим, каждые 200 мс) проверяет наличие новых сообщений на сервере.
Чтобы не вникать в XMLHttpRequest, можно использовать библиотеку Axios. Она декларативна и очень понятна.
Клиент:
<!DOCTYPE html>
<html>
<head>
<title>Обмен сообщениями в режиме реального времени</title>
</head>
<body>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
let localMessages = [];
// начальное обновление локального сообщения
axios.get('http://localhost:8080/messages')
.then(({data}) => localMessages = data.messages);
// обновляем список сообщений
const updateMessages = () => {
axios.get('http://localhost:8080/messages')
.then(({data}) => {
const difference = data.messages.splice(localMessages.length);
difference.forEach(message => {
console.log(message);
localMessages.push(message);
});
})
.catch(console.log);
}
// отправляем сообщение
const sendMessage = text => {
axios.post('http://localhost:8080/messages', {text});
}
// каждые 200 мс проверяем, есть ли новые сообщения
setInterval(updateMessages, 200);
</script>
</body>
</html>
Сервер:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json(), function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// в реальном приложении сообщения хранились бы в базе данных или, в некоторых случаях, в JSON-файлах,
// а не в переменной, которая обнуляется при остановке сервера
let messages = [];
// создаем новое сообщение
app.post('/messages', (req, res) => {
messages.push(req.body.text);
res.json({
success: true
});
});
// получаем все сообщения
app.get('/messages', (req, res) => {
res.json({
messages
});
});
// слушаем все запросы на localhost: 8080.
app.listen(8080, () => console.log('Слушаю порт 8080'));
Заключение
Веб-сокеты являются одной из самых перспективных веб-технологий, которую уже сейчас используют многие разработчики. Она отлично подходит для взаимодействия в режиме реального времени, в том числе в онлайн-играх.