Написание клиентских приложений с помощью веб-сокетов
Веб-сокеты - технология, которая позволяет открыть интерактивную сессию общения между браузером пользователя и сервером. Соединяясь через веб-сокеты, веб-приложения могут осуществлять взаимодействие в реальном времени вместо того, чтобы делать запросы к клиенту о входящих/исходящих изменениях.
Примечание:У нас есть работающий пример чата, части кода из которого используются в статье. Пример будет доступен, когда инфраструктура сайта сможет должным образом поддерживать хостинг примеров с использованием веб-сокетов.
Доступность веб-сокетов
API веб-сокетов доступно в Javascript коде, область видимости которого включает объект DOMWindow
или любой объект, реализующийWorkerUtils
; это означает, что вы можете использовать Web Workers.
Примечание:API веб-сокетов (как и протокол лежащий в его основе) всё ещё проходят этап активной разработки; в настоящее время существует много проблем совместимости с разными браузерами (и даже с разными релизами одного и того же браузера).
Создание объекта WebSocket
Чтобы общаться через протокол веб-сокетов необходимо создать объект WebSocket
; при его создании автоматически происходит попытка открыть соединение с сервером.
Конструктор WebSocket принимает один обязательный и один необязательный параметр:
WebSocket WebSocket( in DOMString url, in optional DOMString protocols);WebSocket WebSocket( in DOMString url, in optional DOMString[] protocols);
url
URL, с которым происходит соединение; это должен быть URL веб-сокет-сервера.
protocols
НеобязательныйМожет быть одной строкой протокола или массивом таких строк. Эти строки используют для индикации под-протоколов; таким образом, один сервер может реализовывать несколько под-протоколов веб-сокетов (к примеру, вам может потребоваться, чтобы сервер мог обрабатывать разные типы взаимодействий в зависимости от определённого под-протокола). Если вы не укажете строку протокола, то будет передана пустая строка.
В конструкторе могут возникать следующие исключения:
SECURITY_ERR
Порт, к которому проводится подключение, заблокирован.
Ошибки подключения
Если ошибка случается во время попытки подключения, то в объектWebSocket
сначала посылается простое событие с именем «error» (таким образом, задействуя обработчикonerror
), потом - событиеCloseEvent
(таким образом, задействуя обработчикonclose
) чтобы обозначить причину закрытия соединения.
Однако, начиная с версии Firefox 11, типичным является получение в консоль от платформы Mozilla расширенного сообщения об ошибке и кода завершения, как то определено вRFC 6455, Section 7.4 посредствомCloseEvent
.
Примеры
Этот простой пример создаёт новый WebSocket, подключаемый к серверуws://www.example.com/socketserver
. В данном примере в конструктор сокета в качестве дополнительного параметра передаётся пользовательский протокол "protocolOne", хотя эта часть может быть опущена.
var exampleSocket = new WebSocket( "ws://www.example.com/socketserver", "protocolOne",);
После выполнения функции,exampleSocket.readyState
будет иметь значениеCONNECTING
.readyState
изменится наOPEN
как только соединение станет готовым к передаче данных.
Если нужно открыть соединение, поддерживающее несколько протоколов, можно передать массив протоколов:
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", [ "protocolOne", "protocolTwo",]);
Когда соединение установлено (что соответствует,readyState
OPEN
),exampleSocket.protocol
сообщит, какой протокол выбрал сервер.
В приведенных выше примерахws
заменяетhttp
, аналогичноwss
заменяетhttps
. Установка соединения через WebSocket зависит от механизма обновления HTTP, таким образом запрос на обновление неявный, когда мы обращаемся к серверу HTTP с помощьюws://www.example.com
илиwss://www.example.com
.
Отправка данных на сервер
Однажды открыв соединение, вы можете передавать данные на сервер. Для осуществления этого, вызовите методsend()
объектаWebSocket
для каждого сообщение, которое желаете отправить:
exampleSocket.send("Вот текст, который будет отправлен серверу.");
Вы можете пересылать данные в виде строки,Blob
, так иArrayBuffer
.
Примечание:До версии 11, Firefox поддерживал отправку данных только в виде строки.
Так как установка соедиения асинхронна и подвержена сбоям, то нет никакой гарантии, что вызов методаsend()
, после создания объекта WebSocket, будет завершен успешно. По крайней мере, мы можем быть уверены, что попытка отправить данные будет иметь место только после того, как соединение будет установлено, определив обработчикonopen
для выполнения этого действия:
exampleSocket.onopen = function (event) { exampleSocket.send("Вот текст, который будет отправлен серверу.");};
Использование JSON для передачи объектов
Одна удобная вещь которую вы можете сделать, это использоватьJSON для пересылки сложных данных на сервер. Например, приложение-чат может взаимодействовать с сервером, используя протокол, реализованный с использованием пакетов данных, инкапсулированных в JSON:
// Отправьте текст всем пользователям через серверfunction sendText() { // Создайте объект содержащий данные, необходимые серверу для обрабоки сообщения от клиента чата. var msg = { type: "message", text: document.getElementById("text").value, id: clientID, date: Date.now(), }; // Отправьте объект в виде JSON строки. exampleSocket.send(JSON.stringify(msg)); // Очистите элемент ввода текста, чтобы получить следующую строку текста от пользователя. document.getElementById("text").value = "";}
Получение сообщений от сервера
WebSockets — это API, управляемый событиями; когда сообщения получены, событие "message" доставлено в функциюonmessage
. Чтобы начать прослушивание входящих данных, вы можете сделать что-то вроде этого:
exampleSocket.onmessage = function (event) { console.log(event.data);};
Получение и интерпретация JSON объектов
Давайте рассмотрим клиентское приложение чата, которое впервые упоминалось в разделеИспользование JSON для передачи объектов. Есть разные типы пакетов данных, которые может получить клиент, например:
- Вход в систему
- Текст сообщения
- Обновление списка пользователей
Код обрабатывающий эти входящие сообщения, может выглядеть так:
exampleSocket.onmessage = function (event) { var f = document.getElementById("chatbox").contentDocument; var text = ""; var msg = JSON.parse(event.data); var time = new Date(msg.date); var timeStr = time.toLocaleTimeString(); switch (msg.type) { case "id": clientID = msg.id; setUsername(); break; case "username": text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>"; break; case "message": text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>"; break; case "rejectusername": text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>"; break; case "userlist": var ul = ""; for (i = 0; i < msg.users.length; i++) { ul += msg.users[i] + "<br>"; } document.getElementById("userlistbox").innerHTML = ul; break; } if (text.length) { f.write(text); document.getElementById("chatbox").contentWindow.scrollByPages(1); }};
Здесь мы используемJSON.parse()
чтобы преобразовать JSON строку в объект, затем обработайте его.
Формат текстовых данных
Текст, полученный через WebSocket должен иметь кодировку UTF-8
До Gecko 9.0, некоторые не символьные значения в допустимом тексте UTF-8 могут привести к разрыву соединения. Теперь Gecko допускает эти значения.
Закрытие соединения
Когда вы закончили использовать соединение WebSocket, закройте его используя методclose()
:
exampleSocket.close();
Перед попыткой закрыть соединение может быть полезно проверить атрибутbufferedAmount
чтобы определить, не переданы ли еще какие-либо данные по сети.
Безопасность
WebSocket не следует использовать в среде со смешанным содержимым: то есть вы не должны открывать незащищенное соединение WebSocket со страницы, загруженной с использованием HTTPS, или наоборот. Фактически, некоторые браузеры явно запрещают это, например Firefox 8 и выше.