Руководство по node.js, часть 8: протоколы http и websocket
Содержание:
- Установление WebSocket-соединения
- Как исправить ошибку 0xc00000005?
- Browser-based example¶
- Функции и особенности WSS Consultant O365:
- HTTP Streaming
- Summary
- Low-level API¶
- Посетите биржи фриланса и удаленной работы
- Передача данных
- Common patterns¶
- A simple example
- Популярные материалы
- Chat example
- Создание приложения исполняемым
- Особенности решения
- REST
- Открытие веб-сокета
- Простой клиент веб-сокетов
- Создание контроллера обработки сообщения
- Пространства и «комнаты»¶
Установление WebSocket-соединения
Протокол работает над TCP.
Это означает, что при соединении браузер отправляет по HTTP специальные заголовки, спрашивая: «поддерживает ли сервер WebSocket?».
Если сервер в ответных заголовках отвечает «да, поддерживаю», то дальше HTTP прекращается и общение идёт на специальном протоколе WebSocket, который уже не имеет с HTTP ничего общего.
Пример запроса от браузера при создании нового объекта :
Описания заголовков:
- GET, Host
- Стандартные HTTP-заголовки из URL запроса
- Upgrade, Connection
- Указывают, что браузер хочет перейти на websocket.
- Origin
- Протокол, домен и порт, откуда отправлен запрос.
- Sec-WebSocket-Key
- Случайный ключ, который генерируется браузером: 16 байт в кодировке Base64.
- Sec-WebSocket-Version
- Версия протокола. Текущая версия: 13.
Все заголовки, кроме и , браузер генерирует сам, без возможности вмешательства JavaScript.
Такой XMLHttpRequest создать нельзя
Создать подобный XMLHttpRequest-запрос (подделать ) невозможно, по одной простой причине: указанные выше заголовки запрещены к установке методом .
Сервер может проанализировать эти заголовки и решить, разрешает ли он с данного домена .
Ответ сервера, если он понимает и разрешает -подключение:
Здесь строка представляет собой перекодированный по специальному алгоритму ключ . Браузер использует её для проверки, что ответ предназначается именно ему.
Затем данные передаются по специальному протоколу, структура которого («фреймы») изложена далее. И это уже совсем не HTTP.
Также возможны дополнительные заголовки и , описывающие расширения и подпротоколы (subprotocol), которые поддерживает данный клиент.
Посмотрим разницу между ними на двух примерах:
-
Заголовок означает, что браузер поддерживает модификацию протокола, обеспечивающую сжатие данных.
Это говорит не о самих данных, а об улучшении способа их передачи. Браузер сам формирует этот заголовок.
-
Заголовок говорит о том, что по WebSocket браузер собирается передавать не просто какие-то данные, а данные в протоколах SOAP или WAMP («The WebSocket Application Messaging Protocol»). Стандартные подпротоколы регистрируются в специальном каталоге IANA.
Этот заголовок браузер поставит, если указать второй необязательный параметр :
При наличии таких заголовков сервер может выбрать расширения и подпротоколы, которые он поддерживает, и ответить с ними.
Например, запрос:
Ответ:
В ответе выше сервер указывает, что поддерживает расширение , а из запрошенных подпротоколов – только SOAP.
Соединение можно открывать как или как . Протокол представляет собой WebSocket над HTTPS.
Кроме большей безопасности, у есть важное преимущество перед обычным – большая вероятность соединения. Дело в том, что HTTPS шифрует трафик от клиента к серверу, а HTTP – нет
Дело в том, что HTTPS шифрует трафик от клиента к серверу, а HTTP – нет.
Если между клиентом и сервером есть прокси, то в случае с HTTP все WebSocket-заголовки и данные передаются через него. Прокси имеет к ним доступ, ведь они никак не шифруются, и может расценить происходящее как нарушение протокола HTTP, обрезать заголовки или оборвать передачу.
А в случае с весь трафик сразу кодируется и через прокси проходит уже в закодированном виде. Поэтому заголовки гарантированно пройдут, и общая вероятность соединения через выше, чем через .
Как исправить ошибку 0xc00000005?
На Windows 7 встречал подобную ошибку, при этом перестают запускаться приложения, которые до этого нормально запускались. Лечится ошибка удалением некоторых обновлений Майкрософт (спасибо, Майкрософт!), а именно kb2859537, kb2872339, kb2882822, kb971033. Делать это лучше из командной строки, вводя команду типа wusa.exe /uninstall /kb:2859537 (в данном случае удалится обновление kb2859537, если его в системе нет, то система об этом сообщит). Ввести команду 4 раза с разными параметрами, это нетрудно. Потом, после перезагрузки компьютер работает нормально. Атоматическое обновления системы потом можно не отключать, Майкрософт уже убрало или исправило конфликтные обновления.
в избранное ссылка отблагодарить
Часто возникает при некорректной работе программ, приложений.
На мониторе высвечивается ошибка либо на русском, либо на английском (зависит от языка операционной системы):
- The application was unable to start correctly (0xc0000005). Click OK to close the application.
- Ошибка при запуске приложения (0хс0000005). Для выхода из приложения нажмите кнопку «ОК».
Что в первом, что во втором варианте — это одна и таже ошибка, просто на разных языках указана.
Может возникнуть при запуске любого приложения: плеера AIMP3, Skype, браузера Chrome, Avatar, Firefox, Opera, Winword, Iexplorer, прочих.
Проблема возникает из-за обновлений, которые скачаны программой и установлены. Происходит сбой в работе, который и приводит к подобным сообщениям.
Чтобы исправить, нужно удалить обновления, для этого заходим:
«Пуск» -> «Панель управления» -> «Программы и компоненты» -> «Просмотр установленных обновлений».
Удаляем скачанные KB2859537, KB2872339 .
Следом заходим в «Центр обновлений Windows» — снимаем галки с загрузки обновлений.
Browser-based example¶
Here’s an example of how to run a WebSocket server and connect from a browser.
Run this script in a console:
#!/usr/bin/env python # WS server that sends messages at random intervals import asyncio import datetime import random import websockets async def time(websocket, path): while True now = datetime.datetime.utcnow().isoformat() + "Z" await websocket.send(now) await asyncio.sleep(random.random() * 3) start_server = websockets.serve(time, "127.0.0.1", 5678) asyncio.get_event_loop().run_until_complete(start_server) asyncio.get_event_loop().run_forever()
Then open this HTML file in a browser.
Функции и особенности WSS Consultant O365:
- Создание прозрачного процесса управления отделами/сотрудниками.
- Адаптация процессов совместной работы с документами в рамках обращения: создание документов из шаблонов, отслеживание этапов движения документов.
- Настройка удалённой работы сотрудников в ресурсе: доступ к информации (документы, файлы, аудио), возможность аудио/видеоконференций.
- Автоматизация системы аналитики, настройка конструктора отчётов.
- Создание централизованного хранилища документов.
- Эффективность и простота создания обращения.
- Простой и понятный интерфейс с возможностью отслеживания состояния задач.
- Организация эффективной коммуникации с исполнителями.
- Адаптированный интерфейс для мобильных устройств.
- Возможность организовать совместную работу с документами в рамках обращения.
Для всех пользователей, будет доступен корпоративный портал, в котором можно просмотреть актуальные корпоративные новости, просмотреть ближайшие мероприятия, поднять тему на форуме, а также получить доступ к базе всех внутренних документов. Кроме этого, все зарегистрированные сотрудники, получают доступ к встроенным веб-сервисам Office 365, для организации удаленной работы, таким как: Microsoft Teams, Planner, OneDrive.
Так как решение направлено на корпоративный сегмент рынка, и связано с работой с конфиденциальными и персонализированными данными, мы позаботились о безопасности. WSS Consultant O365 включает в себя двухфакторную аутентификацию, DLP систему(предупреждение потери данных), управление пользовательскими права доступа, шифрование данных в Office 365, расширенную защиту от угроз Exchange Online Protection, Active Directory Federation Service. Все персональные данные, хранящиеся в базе WSS Consultant O365 полностью соответствуют требования законодательства РФ. Кроме этого, безопасность в решении представлена Etoken, FIDO 2 и КриптоПро.
Гибкая стоимость решения, основанная на количестве сотрудников и сроках действия лицензии, позволяет выбрать нужные параметры и не переплачивать, сэкономив бюджет компании.
Запишитесь на бесплатный демо-тест уже сегодня, и оцените все преимущества WSS Consultant O365:
HTTP Streaming
HTTP Streaming — provides a long-lived connection for instant and continuous data push (Image from realtimeapi.io)
The client makes an HTTP request, and the server trickles out a response of indefinite length (it’s like polling infinitely).HTTP streaming is performant, easy to consume and can be an alternative to WebSockets.
Issue: Intermediaries can interrupt the connection (e.g. timeout, intermediaries serving other requests in a round-robin manner). In such cases, it cannot guarantee the complete realtimeness.
00:00:00 CLIENT-> I need cakes 00:00:01 SERVER-> Wait for a moment.00:00:01 SERVER-> Cake-1 is in process.00:00:02 SERVER-> Have cake-1.00:00:02 SERVER-> Wait for cake-2.00:00:03 SERVER-> Cake-2 is in process.00:00:03 SERVER-> You must be enjoying cake-1.00:00:04 SERVER-> Have cake-2.00:00:04 SERVER-> Wait for cake-3.00:00:05 CLIENT-> Enough, I'm full.
Summary
WebSocket is a modern way to have persistent browser-server connections.
- WebSockets don’t have cross-origin limitations.
- They are well-supported in browsers.
- Can send/receive strings and binary data.
The API is simple.
Methods:
- ,
- .
Events:
- ,
- ,
- ,
- .
WebSocket by itself does not include reconnection, authentication and many other high-level mechanisms. So there are client/server libraries for that, and it’s also possible to implement these capabilities manually.
Sometimes, to integrate WebSocket into existing project, people run WebSocket server in parallel with the main HTTP-server, and they share a single database. Requests to WebSocket use , a subdomain that leads to WebSocket server, while goes to the main HTTP-server.
Surely, other ways of integration are also possible.
Low-level API¶
Exceptions
- exception
-
Exception raised when a handshake request or response is invalid.
- exception
-
Exception raised when an operation is forbidden in the current state.
- exception
-
Exception raised when an URI is invalid.
Opening handshake
The module deals with the WebSocket opening
handshake according to .
It provides functions to implement the handshake with any existing HTTP
library. You must pass to these functions:
- A set_header function accepting a header name and a header value,
- A get_header function accepting a header name and returning the header
value.
The inputs and outputs of get_header and set_header are
objects containing only ASCII characters.
Some checks cannot be performed because they depend too much on the
context; instead, they’re documented below.
To accept a connection, a server must:
- Read the request, check that the method is GET, and check the headers with
, - Send a 101 response to the client with the headers created by
if the request is valid; otherwise, send a 400.
To open a connection, a client must:
- Send a GET request to the server with the headers created by
, - Read the response, check that the status code is 101, and check the headers
with .
- (set_header)
-
Build a handshake request to send to the server.
Return the key which must be passed to .
- (get_header)
-
Check a handshake request received from the client.
If the handshake is valid, this function returns the key which must be
passed to .Otherwise, it raises an exception and the server
must return an error, usually 400 Bad Request.This function doesn’t verify that the request is an HTTP/1.1 or higher GET
request and doesn’t perform Host and Origin checks. These controls are
usually performed earlier in the HTTP request handling code. They’re the
responsibility of the caller.
- (set_header, key)
-
Build a handshake response to send to the client.
key comes from .
- (get_header, key)
-
Check a handshake response received from the server.
key comes from .
If the handshake is valid, this function returns .
Otherwise, it raises an exception.
This function doesn’t verify that the response is an HTTP/1.1 or higher
response with a 101 status code. These controls are the responsibility of
the caller.
Data transfer
The module implements data framing as specified in
.
It deals with a single frame at a time. Anything that depends on the sequence
of frames is implemented in .
- class (fin, opcode, data)
-
-
Alias for field number 2
-
Alias for field number 0
-
Alias for field number 1
-
- (reader, mask, *, max_size=None)
-
Read a WebSocket frame and return a object.
reader is a coroutine taking an integer argument and reading exactly this
number of bytes, unless the end of file is reached.mask is a telling whether the frame should be masked, ie.
whether the read happens on the server side.If max_size is set and the payload exceeds this size in bytes,
is raised.This function validates the frame before returning it and raises
if it contains incorrect values.
- (frame, writer, mask)
-
Write a WebSocket frame.
frame is the object to write.
writer is a function accepting bytes.
mask is a telling whether the frame should be masked, ie.
whether the write happens on the client side.This function validates the frame before sending it and raises
if it contains incorrect values.
- (data)
-
Parse the data in a close frame.
Return (code, reason) when code is an and reason a
.Raise or if the
data is invalid.
- (code, reason)
-
Serialize the data for a close frame.
This is the reverse of .
URI parser
The module implements parsing of WebSocket URIs
according to .
- (uri)
-
This function parses and validates a WebSocket URI.
If the URI is valid, it returns a namedtuple (secure, host, port,
resource_name)Otherwise, it raises an exception.
Посетите биржи фриланса и удаленной работы
Поскольку тенденция работать дома, вместо того, чтобы толкаться в утренние часы в общественном транспорте, набирает обороты, то есть смысл подготовиться к новым способам заработка уже сегодня. Кроме того, в ближайшие 5 лет в России ожидается бум дистанционной деятельности, а к 2020 году каждый пятый офисный сотрудник будет удаленным. Кроме того, уже сегодня многие россияне работают на двух работах: в офисе и удаленно.
Фраза коллеги о том, что он зарабатывает «не только на работе» уже никого не удивляет. Многие понимающе кивают: занялся фрилансом.
Возрастает интерес к дистанционному обучению с целью получить новую интернет-профессию, хотя такой вид получения знаний в России пока начинает развиваться.
Многие россияне интересуются возможностями фриланса и удаленной работы. Конечно, это не тождественные понятия. Удаленная работа предполагает постоянную занятость у конкретного работодателя с регулярной выплатой заработной платы. На фрилансе заработать можно больше, но работник может рассчитывать только на свою активную жизненную позицию, поскольку ему приходится постоянно искать заказы.
Работодателей устраивает такой формат работы подчиненных, поскольку он позволяет сэкономить около 170 000руб. в год (при расчете на одного работника). Начать работать удаленно может каждый. Освоение нового формата деятельности лучше начать с биржи фрилансеров. В Сети Вы сможете найти большое количество бирж для фрилансеров: зарубежных и отечественных, предназначенных конкретным специалистам и всем желающим.
www.weblancer.net — Биржа фриланса с богатым выбором предложений в самых разных областях: копирайтинг, дизайн, таргетированная реклама, продвижение на YouTube, декорации квартир и многое другое.
moguza.ru — Это магазин он-лайн услуг, которые выполняются по фиксированной цене. На сайте зарегистрировано 12 000 исполнителей, и уже исполнено заказов на 10 млн. рублей. В настоящий момент на ресурсе представлено 10 486 предложений.
www.freelancejob.ru — Это тоже биржа фриланса. Быть может она не так известна, как другие ресурсы, которые у всех «на слуху», но за счет этого на ней конкуренция при получении заказа может оказаться значительно ниже. Предложения работы по копирайтингу, рерайтингу, доработке сайтов, работа для фотографов, программистов,сочинение музыки.
Передача данных
Поток данных в WebSocket состоит из «фреймов», фрагментов данных, которые могут быть отправлены любой стороной, и которые могут быть следующих видов:
- «текстовые фреймы» – содержат текстовые данные, которые стороны отправляют друг другу.
- «бинарные фреймы» – содержат бинарные данные, которые стороны отправляют друг другу.
- «пинг-понг фреймы» используется для проверки соединения; отправляется с сервера, браузер реагирует на них автоматически.
- также есть «фрейм закрытия соединения» и некоторые другие служебные фреймы.
В браузере мы напрямую работаем только с текстовыми и бинарными фреймами.
Метод WebSocket может отправлять и текстовые и бинарные данные.
Вызов принимает в виде строки или любом бинарном формате включая , и другие. Дополнительных настроек не требуется, просто отправляем в любом формате.
При получении данных, текст всегда поступает в виде строки. А для бинарных данных мы можем выбрать один из двух форматов: или .
Это задаётся свойством , по умолчанию оно равно , так что бинарные данные поступают в виде -объектов.
Blob – это высокоуровневый бинарный объект, он напрямую интегрируется с , и другими тегами, так что это вполне удобное значение по умолчанию. Но для обработки данных, если требуется доступ к отдельным байтам, мы можем изменить его на :
Common patterns¶
You will usually want to process several messages during the lifetime of a
connection. Therefore you must write a loop. Here are the basic patterns for
building a WebSocket server.
Consumer
For receiving messages and passing them to a coroutine:
async def consumer_handler(websocket, path): async for message in websocket await consumer(message)
In this example, represents your business logic for processing
messages received on the WebSocket connection.
Iteration terminates when the client disconnects.
Producer
For getting messages from a coroutine and sending them:
async def producer_handler(websocket, path): while True message = await producer() await websocket.send(message)
In this example, represents your business logic for generating
messages to send on the WebSocket connection.
raises a
exception when the client disconnects,
which breaks out of the loop.
Both
You can read and write messages on the same connection by combining the two
patterns shown above and running the two tasks in parallel:
async def handler(websocket, path): consumer_task = asyncio.ensure_future( consumer_handler(websocket, path)) producer_task = asyncio.ensure_future( producer_handler(websocket, path)) done, pending = await asyncio.wait( consumer_task, producer_task], return_when=asyncio.FIRST_COMPLETED, ) for task in pending task.cancel()
A simple example
To open a websocket connection, we need to create using the special protocol in the url:
There’s also encrypted protocol. It’s like HTTPS for websockets.
Always prefer
The protocol is not only encrypted, but also more reliable.
That’s because data is not encrypted, visible for any intermediary. Old proxy servers do not know about WebSocket, they may see “strange” headers and abort the connection.
On the other hand, is WebSocket over TLS, (same as HTTPS is HTTP over TLS), the transport security layer encrypts the data at sender and decrypts at the receiver. So data packets are passed encrypted through proxies. They can’t see what’s inside and let them through.
Once the socket is created, we should listen to events on it. There are totally 4 events:
- – connection established,
- – data received,
- – websocket error,
- – connection closed.
…And if we’d like to send something, then will do that.
Here’s an example:
For demo purposes, there’s a small server server.js written in Node.js, for the example above, running. It responds with “Hello from server, John”, then waits 5 seconds and closes the connection.
So you’ll see events → → .
That’s actually it, we can talk WebSocket already. Quite simple, isn’t it?
Now let’s talk more in-depth.
Популярные материалы
Chat example
Let’s review a chat example using browser WebSocket API and Node.js WebSocket module https://github.com/websockets/ws. We’ll pay the main attention to the client side, but the server is also simple.
HTML: we need a to send messages and a for incoming messages:
From JavaScript we want three things:
- Open the connection.
- On form submission – for the message.
- On incoming message – append it to .
Here’s the code:
Server-side code is a little bit beyond our scope. Here we’ll use Node.js, but you don’t have to. Other platforms also have their means to work with WebSocket.
The server-side algorithm will be:
- Create – a set of sockets.
- For each accepted websocket, add it to the set and setup event listener to get its messages.
- When a message received: iterate over clients and send it to everyone.
- When a connection is closed: .
Here’s the working example:
You can also download it (upper-right button in the iframe) and run locally. Just don’t forget to install Node.js and before running.
Создание приложения исполняемым
Несмотря на то, что пакет этого сервиса может быть в составе web-приложения и
WAR файлов,
более простой подход, продемонстрированный ниже создает отдельное самостоятельное приложение.
Вы упаковываете все в единый, исполняемый JAR-файл, который запускается через хорошо знакомый
старый Java-метод. Попутно, вы используете поддержку Spring для встроенного
Tomcat
контейнера сервлетов как HTTP среду выполнения вместо развертывания на сторонний экземпляр.
Метод передает управление вспомогательному классу
, предоставляя
как аргумент его методу. Это говорит Spring о том, чтобы
прочитать аннотацию метаданных из и управлять им
как компонентом в Spring Application Context.
Аннотация сообщает Spring о запуске рекурсивного
поиска в пакете и потомках классов, отмеченных прямо или
косвенно Spring аннотацией . При этом гарантируется,
что Spring найдет и зарегистрирует ,
потому что он отмечен , что в свою очередь является
своего рода аннотацией.
Сборка исполняемого JAR
Вы можете собрать единый исполняемый JAR-файл, который содержит все необходимые зависимости,
классы и ресурсы. Это делает его легким в загрузке, версионировании и развертывании сервиса как
приложения на протяжении всего периода разработки, на различных средах и так далее.
Затем вы можете запустить JAR-файл:
Если вы используете Maven, вы можете запустить приложение, используя ,
либо вы можете собрать приложение с и запустить JAR примерно так:
Процедура, описанная выше, создает исполняемый JAR. Вы также можете вместо него
собрать классический WAR-файл.
Если вы используете Gradle, вы можете запустить ваш сервис из командной строки:
Если вы используете Maven, то можете запустить ваш сервис таким образом:
.
Как вариант, вы можете запустить ваш сервис напрямую из Gradle примерно так:
С mvn — .
Сервис должен быть поднят и запущен через несколько секунд.
Особенности решения
Система WSS Docs обладает следующим функционалом:
- Настраиваемые процессы согласования, исполнения документов
- Интуитивно понятный интерфейс работы с документами
- Настраиваемые маршруты согласования документов
- Последовательное согласование
- Параллельное согласование
- Комбинации последовательного и параллельного согласования
- Поиск и фильтрация
- Поиск документов по фильтрам, настроенным на любые поля карточки
- Полнотекстовый поиск документов с учётом русской морфологии
- Настраиваемые представления
- Оповещения системы по email
- По всем событиям по документу
- Возможность принятия решений из письма
- Контроль исполнительской дисциплины
- Контроль сроков согласования
- Контроль сроков исполнения поручений
- Ежедневные напоминания обо всех просроченных документах
- Система заместителей
- Широкие возможности регистрации документов, нумерация документов
- Шаблоны регистрационных номеров
- Автоматическая нумерация документов и проектов документов
- Возможность задавать регистрационный номер как из системы, так задавать номер вручную
- Возможность зарегистрировать документ задним числом
- Просмотр родительских и дочерних документов и всей иерархии документа
- Работа с файлами документов
- Возможность прикреплять к карточке документа произвольное количество файлов. Возможность комментировать прикрепленные файлы
- Отслеживание версий каждого прикрепленного файла, сравнение версий
- Разграничение доступа к карточкам и файлам документов
- Разграничение доступа на основе ролей и правил
- Доступ может устанавливаться на документ в целом, на файлы, на отдельные поля карточки
- Запись всех действий и решений пользователей по документу в истории решений, в которой фиксируется:
- Пользователь, принявший решение, его роль
- Название решения, Время принятия решения
- Все оповещенные по решению сотрудники
REST
The architectural style, REST (REpresentational State Transfer) is by far the most standardized way of structuring the web APIs for requests. REST is purely an architectural style based on several principles. The APIs adhering to REST principles are called RESTful APIs. REST APIs use a request/response model where every message from the server is the response to a message from the client. In general, RESTful APIs uses HTTP as its transport protocol. For such cases, lookups should use requests. , , and requests should be used for mutation, creation, and deletion respectively (avoid using requests for updating information).
Открытие веб-сокета
Когда создан, он тут же сам начинает устанавливать соединение.
Браузер, при помощи специальных заголовков, спрашивает сервер: «Ты поддерживаешь Websocket?» и если сервер отвечает «да», они начинают работать по протоколу WebSocket, который уже не является HTTP.
Вот пример заголовков для запроса, который делает .
- – источник текущей страницы (например ). Объект WebSocket по своей природе не завязан на текущий источник. Нет никаких специальных заголовков или других ограничений. Старые сервера все равно не могут работать с WebSocket, поэтому проблем с совместимостью нет. Но заголовок важен, так как он позволяет серверу решать, использовать ли WebSocket с этим сайтом.
- – сигнализирует, что клиент хотел бы изменить протокол.
- – запрошен протокол «websocket».
- – случайный ключ, созданный браузером для обеспечения безопасности.
- – версия протокола WebSocket, текущая версия 13.
Запрос WebSocket нельзя эмулировать
Мы не можем использовать или для создания такого HTTP-запроса, потому что JavaScript не позволяет устанавливать такие заголовки.
Если сервер согласен переключиться на WebSocket, то он должен отправить в ответ код 101:
Здесь – это , перекодированный с помощью специального алгоритма. Браузер использует его, чтобы убедиться, что ответ соответствует запросу.
После этого данные передаются по протоколу WebSocket, и вскоре мы увидим его структуру («фреймы»). И это вовсе не HTTP.
Могут быть дополнительные заголовки и , описывающие расширения и подпротоколы.
Например:
-
означает, что браузер поддерживает сжатие данных. Расширение – это что-то, связанное с передачей данных, расширяющее сам протокол WebSocket. Заголовок отправляется браузером автоматически со списком всевозможных расширений, которые он поддерживает.
-
означает, что мы будем передавать не только произвольные данные, но и данные в протоколах SOAP или WAMP (The WebSocket Application Messaging Protocol» – «протокол обмена сообщениями WebSocket приложений»). То есть, этот заголовок описывает не передачу, а формат данных, который мы собираемся использовать. Официальные подпротоколы WebSocket регистрируются в каталоге IANA.
Этот необязательный заголовок ставим мы сами, передавая массив подпротоколов вторым параметром , вот так:
Сервер должен ответить перечнем протоколов и расширений, которые он может использовать.
Например, запрос:
Ответ:
Здесь сервер отвечает, что поддерживает расширение – deflate-frame и может использовать только протокол SOAP из всего списка запрошенных подпротоколов.
Простой клиент веб-сокетов
С точки зрения веб-страницы функциональность веб-сокетов легко понять и использовать. Первый шаг — это создать объект WebSocket и передать ему URL. Код для этого подобен следующему:
Строка URL начинается с текста ws://, который идентифицирует подключение типа веб-сокет. Этот URL указывает файл веб-приложения на сервере (в данном случае это сценарий socketServer.php).
Стандарт веб-сокетов также поддерживает URL, которые начинаются с текста wss://, что указывает на требование использовать безопасное, зашифрованное подключение (точно так же, как и при запросе веб-страницы указывается URL, начинающийся с https:// вместо http://).
Веб-сокеты могут подключаться не только к своему веб-серверу. Веб-страница может открыть подключение к серверу веб-сокетов, исполняющемуся на другом веб-сервере, не требуя для этого никаких дополнительных усилий.
Само обстоятельство создания объекта WebSocket понуждает страницу пытаться подключиться к серверу. Дальше надо использовать одно из четырех событий объекта WebSocket: onOpen (при установлении подключения), onError (когда возникает ошибка), onClose (при закрытии подключения) и onMessage (когда страница получает сообщение от сервера):
Например, в случае успешного подключения неплохо бы отправить соответствующее подтверждающее сообщение. Такое сообщение доставляется с помощью метода send() объекта WebSocket, которому в качестве параметра передается обычный текст. Далее приведена функция, которая обрабатывает событие onopen и отправляет сообщение:
Предположительно, веб-сервер получит это сообщение и даст на него ответ.
События onError и onClose можно использовать для отправки извещений посетителю веб-страницы. Но безоговорочно самым важным является событие onMessage, которое срабатывает при получении новых данных от сервера. Опять же, код JavaScript для обработки этого события не представляет никаких сложностей — мы просто извлекаем текст сообщения из свойства data:
Если веб-страница решит, что вся ее работа выполнена, она может закрыть подключение, используя метод disconnect():
Из этого обзора веб-сокетов можно видеть, что использование сервера веб-сокетов стороннего разработчика не представляет никаких трудностей — нам нужно лишь знать, какие сообщения отправлять, а какие — ожидать.
Чтобы заставить подключение веб-сокетов работать, выполняется большой объем работы за кулисами. Прежде всего, веб-страница устанавливает связь по обычному стандарту HTTP. Потом это подключение нужно повысить до подключения веб-сокетов, позволяющего свободную двустороннюю связь. На этом этапе возможны проблемы, если между компьютером клиента и веб-сервером находится прокси-сервер (как, например, в типичной корпоративной сети). Прокси-сервер может отказаться сотрудничать и разорвет подключение. Эту проблему можно решить, обнаруживая неудачное подключение (посредством события onError объекта WebSocket) и применяя один из заполнителей (polyfills) для сокетов, описанных на веб-сайте GitHub. Эти заполнители применяют метод опроса, чтобы эмулировать подключение веб-сокетов.
Создание контроллера обработки сообщения
В подходе Spring при работе с STOMP сообщениями, STOMP сообщения могут быть перенаправлены к
классам. К примеру, обрабатывает
сообщения для .
контроллер краток и прост, но там много чего происходит. Давайте подробнее рассмотрим шаг за шагом.
аннотация гарантирует, что если сообщение отправляется на ,
то будет вызван метод.
Полезная часть сообщения привязана к объекту, который передается в .
Внутри реализации метода симулируется обработка сообщения, останавливая поток выполнения на три секунды.
Это демонстрирует, что после того, как клиент отправил сообщение, серверу понадобится сколь угодно много
времени для обработки сообщения асинхронно. Клиент может продолжить свою работу без необходимости ожидания
ответа.
После трехсекундной задержки, метод создает объект и
возвращает его. Возвращаемое значение рассылается всем подписчикам на ,
как это определено в аннотации .
Пространства и «комнаты»¶
В протоколе WebSocket существуют такие понятия, как пространства и «комнаты». По умолчанию посылаемые данные отправляются всем сокетам, но принимают эти данные лишь некоторые из них. Получается, что в определенные моменты времени будет установлено избыточное количество соединений. Чтобы избежать этого, используйте пространства.
Пространства позволяют изолировать одни сокеты от других.
app.js
В приведенном примере с помощью метода на сервере определяются два пространства: и . На клиентской стороне подключение к тому или иному пространству происходит в зависимости от текущего маршрута. Таким образом, при отправке данных, например, из пространства , об этом будут оповещены только сокеты этого пространства. По умолчанию все сокеты находятся в пространстве .
Также и в пределах пространства можно распределять сокеты по так называемым «комнатам».
Чтобы отнести сокет к определенной «комнате» используется метод пространства , который принимает имя «комнаты» (задается пользователем модуля ). Для вынесения сокета из комнаты используйте метод .
Отправка данных в «комнату» осуществляется с помощью метода .
Обработка инициируемых в пределах «комнаты» событий осуществляется с использованием метода .