WebSocket — протокол для обмена сообщениями между браузером и веб-сервером в режиме реального времени. Т.е. он позволяет увеличить скорость обмена данными между сервером и клиентом за счет более легкого, нежели HTTP протокола и организации постоянного соединения. Читать википедию или доки мозиллы (En или Ru). Проверить поддержку WebSocket в браузере можно введением названия одноименного конструктора в консоли веб-клиента, большинство браузеров найдут существующий объект. Основные задачи использования сокетов – задачи реального времени. Чаты, уведомления, игровые клиенты, онлайн слежение за показателями.
Создание WebSocket клиента
Давайте создадим клиента (WebSocket-клиента) для работы на сокетах.
Создадим index.html
со стандартным набором тегов и HTML-форму внутри. При помощи Emmet можно развернуть строку (Посмотреть как работает Emmet):
!>form[name=messages]>.row*3>input^^#status
Получится HTML-код
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="" name="messages">
<div class="row"><input type="text"></div>
<div class="row"><input type="text"></div>
<div class="row"><input type="text"></div>
</form>
<div id="status"></div>
</body>
</html>
Поправим форму, внеся название полям и изменяя последнее однострочное текстовое поле на кнопку отправки формы.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<h1>Пример работы с WebSocket</h1>
<form action="" name="messages">
<div class="row">Имя: <input type="text"></div>
<div class="row">Текст: <input type="text"></div>
<div class="row"><input type="submit" value="Поехали"></div>
</form>
<div id="status"></div>
<script>
</script>
</body>
</html>
В разделе script
создадим переменную socket
на основе конструктора WebSocket. В качестве аргумента передадим URL с протоколом «ws» (а для использования защищенного соединения используется wss, при этом нужно не забывать о SSL сертификате).
var socket = new WebSocket("ws://echo.websocket.org");
Адрес ws://echo.websocket.org указывает на расположение Websoket-сервера. Сейчас это эхо-сервер, он отвечает сообщением, которые мы будем ему отправлять.
Получим ссылку на HTML-элемент с идентификатором «status» для отображения дальнейшего статуса работы (Посмотреть как работает document.querySelectorAll() ):
var status = document.querySelector("#status");
У объекта socket есть четыре основных события:
onopen
— при установке/открытии соединенияonclose
– при закрытии соединенияonmessage
– при получении данныхonerror
– при возникновении ошибки
Закрытие соединения может происходить по плану, когда мы явно отключаемся от сокета, или не запланированно, при проблемах связи или прекращении работы сокет-сервера. Выяснить было ли соединение закрыто по плану или нет, можно при помощи свойства event.wasClean
объекта события.
Примечания: работу по созданию соединения нужно проводить после полной загрузки окна, иначе можно при отправке сообщения на тестовый сокет-сервер можно получить Uncaught DOMException: Failed to execute ‘send’ on ‘WebSocket’: Still in CONNECTING state. CONNECTING – это одна из констант, которые назначаются свойству readyState
объекта WebSocket
.
CONNECTING (ПОДКЛЮЧЕНИЕ) | 0 | Подключение еще не открыто. |
OPEN (ОТКРЫТО) | 1 | Соединение открыто и готово к работе. |
CLOSING (ЗАКРЫТИЕ) | 2 | Соединение находится в процессе закрытия. |
CLOSED (ЗАКРЫТО) | 3 | Соединение закрыто или не может быть открыто. |
Полное содержимое раздела script
, при котором должна появиться строка статуса «соединение установлено».
window.onload = function(){
var socket = new WebSocket("ws://echo.websocket.org");
var status = document.querySelector("#status");
socket.onopen = function() {
status.innerHTML = "cоединение установлено";
};
socket.onclose = function(event) {
if (event.wasClean) {
status.innerHTML = 'cоединение закрыто';
} else {
status.innerHTML = 'соединения как-то закрыто';
}
status.innerHTML += '<br>код: ' + event.code + ' причина: ' + event.reason;
};
socket.onmessage = function(event) {
status.innerHTML = "пришли данные " + event.data;
};
socket.onerror = function(event) {
status.innerHTML = "ошибка " + event.message;
};
}
Для отправки сообщения в вебсокет, используется метод send объекта WebSocket. Метод принимает строковый аргумент. Добавим имена нашим текстовым полям:
<form action="" name="messages">
<div class="row">Имя: <input type="text" name="fname"></div>
<div class="row">Текст: <input type="text" name="msg"></div>
<div class="row"><input type="submit" value="Поехали"></div>
</form>
и пропишем реакцию на отправку формы, помещая в send() имя и текст отправителя:
//в рамках onload document.forms["messages"].onsubmit = function(){ let fname = this.fname.value; let msg = this.msg.value; socket.send(`${fname} ${msg}`); return false; }
let, обратные косые кавычки и знак доллара с фигурными скобками – это все стиль JavaScript2015. Если вы ещё не сталкивались с ним, то код var вместо let также будет работать (let – оператор объявления переменной с блочным уровнем видимости this linkcateringvisit their website, обратные косые кавычки позволяют создавать мультистроки, т.е. строки с переносами строки при редактировании текста, ${} – возможность подстановки переменных в строку без указания бесчисленного количества операторов склеивания +):
document.forms["messages"].onsubmit = function(){
var fname = this.fname.value;
var msg = this.msg.value;
socket.send(fname + ' ' + msg);
return false;
}
Но в нашем примере останется первый способ.
Теперь при отправке данных из формы, ниже будет появляться текст «пришли данные» и далее будет идти фрагмент самими данными с эхо-сервера.
Отправка данных в формате JSON
При разработке часто требуется отправлять и принимать структурированные данные. Даже в нашей простой форме при отправке имени пользователя и текста сообщения, не структурируя данные, мы чувствуем неудобство: как сервер будет их использовать при необходимости вставить данные в базу. А если это будут координаты элемента на странице, как в случае с играми? Этот и другие вопросы заставляют нас обратить внимание на формат JSON.
Перепишем код нашего клиента так, чтобы он отправлял данные в этом формате, а при получении строки от эхо-сервера, конвертировал её снова в JSON.
Будем использовать методы встроенного в JavaScript объекта JSON:
JSON.stringify(obj)
конвертация JavaScript-объекта (на самом деле и массив можно) в строкуJSON.parse(string)
получение из строки объекта в JSON-нотации
document.forms["messages"].onsubmit = function(){
let message = {
name:this.fname.value,
msg: this.msg.value
}
socket.send(JSON.stringify(message));
return false;
}
socket.onmessage = function(event) {
let message = JSON.parse(event.data);
status.innerHTML = `пришли данные: <b>${message.name}</b>: ${message.msg}`;
};
Теперь на эхо-сервер отправляется JSON сериализованный в строку, а назад получается строка, из которой мы опять получаем JS-объект. Посмотреть реализацию вебсокета на Codepen.