Доброго времени суток, уважаемые хабровцы.
На моем нынешнем месте работы было принято решение перевести взаимодействие с веб-клиентом на WebSocket. Серверная часть написана на Java с использованием фреймворка Spring. В этой статье я хотел поделиться особенностью устройства Spring WebSocket. WebSocket обеспечивает двустороннюю связь между клиентом и сервером с использованием одного TCP-соединения.
Протокол состоит из двух этапов:
Запрос Handshake использует запрос HTTP GET, в результате чего соединение обновляется до WebSocket.
В этой статье мы подробно рассмотрим механизм установления связи между клиентом и сервером, прокачки соединения с WebSocket и пересылки сообщения в Spring-приложение.
В анализе мы будем использовать конфигурацию на основе Spring-WebSocket и аннотаций.
Создание класса конфигурации
Итак, сначала нам нужно объявить точку доступа, к которой будет обращаться клиент для создания соединения и отправки данных.Чтобы использовать WebSocket в классе конфигурации, нам нужно использовать аннотацию @EnableWebSocket. Из описания этой аннотации следует, что нам необходимо реализовать интерфейс WebSocketConfigurer с нашим классом конфигурации.
Интерфейс WebSocketConfigurer содержит один метод. RegisterWebSocketHandlers (реестр WebSocketHandlerRegistry) .
С помощью входного параметра WebSocketHandlerRegistry мы добавляем обработчики (WebSocketHandler) входящих сообщений на определенный URL. Давайте посмотрим, как работает аннотация @EnableWebSocket более подробно.
Основная задача этой аннотации — импортировать класс конфигурации DelegatingWebSocketConfiguration, который с помощью @Autowired будет получать экземпляры интерфейса WebSocketConfigurer (наш класс конфигурации).@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Import(DelegatingWebSocketConfiguration.class) public @interface EnableWebSocket { }
Эти экземпляры WebSocketConfigurer используются в родительском классе WebSocketConfigurationSupport для создания bean-компонента HandlerMapping. Создание bean-компонента HandlerMapping необходимо, чтобы DispatcherServlet мог позже определить обработчик для этого URL-адреса.
Чтобы преобразовать WebSocketHandler в экземпляр HandlerMapping, нам нужны адаптеры WebSocketHttpRequestHandler и WebSocketHandlerMapping.
Используя WebSocketHttpRequestHandler, мы преобразуем WebSocketHandler в HttpRequestHandler. А затем, используя комбинацию url, по которому мы ждём запрос на открытие WebSocket, и HttpRequestHandler, мы создадим экземпляр WebSocketHandlerMapping, который будет зарегистрирован в DispatcherServlet для обработки HTTP-запроса.
Когда клиент отправляет запрос на открытие соединения WebSocket, запрос поступает через DispatcherServlet к методу handleRequest (HttpServletRequest servletRequest, HttpServletResponse servletResponse) наш декоратор WebSocketHttpRequestHandler.
Этот метод вызывает перехватчики, объявленные в классе конфигурации при настройке WebSocketHandlers, и вызывает метод doHandshake, стандартный или пользовательский экземпляр HandshakeHandler.
Обработка запроса на рукопожатие
Давайте подробнее рассмотрим, как работает метод doHandshake. Именно здесь происходит вся магия преобразования соединения в WebSockets. Но сначала давайте посмотрим на параметры запроса пользователя и ответа сервера.
Типичный пример пользовательского запроса выглядит так: GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
- Origin — содержит URL-адрес, с которого сделан запрос.
Используется для проверки действительных адресов.
- Sec-WebSocket-Protocol — определяет набор подпротоколов, например STOMP, о котором речь пойдет в будущих статьях.
- Sec-WebSocket-Key — это случайный ключ, генерируемый браузером: 16 байт, в кодировке Base64.
- Sec-WebSocket-Version — версия протокола.
- Sec-WebSocket-Extensions — дополнительные расширения, например, permessage-deflate указывает, что сообщения будут передаваться в сжатом виде.
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Код ответа HTTP 101 указывает на переключение протокола, в нашем случае на WebSocket. Sec-WebSocket-Accept — расчетное значение на основе переданного Sec-WebSocket-Key и константы «258EAFA5-E914-47DA-95CA-C5AB0DC85B11» — по сути это подтверждение от сервера о том, что он готов инициировать соединение WebSocket. Работу метода doHandshake схематически можно представить следующим образом:
Запросить стратегию обновления до WebSocket
Стратегии обновления соединения, доступные в настоящее время- TomcatRequestUpgradeStrategy
- JettyRequestUpgradeStrategy
- Стратегия UndertowRequestUpgrade
- СтеклоРыбаЗапросОбновитьСтратегия
- WebLogicRequestUpgradeStrategy
- WebSphereRequestUpgradeStrategy
* ?Экземпляр EndPoint создается путем упаковки WebSocketHandler в StandardWebSocketHandlerAdapter, который является наследником EndPoint. Для создания сеанса используется StandardWebSocketSession. ** Для обновления HttpServletRequest используем стандартный метод обновления этого интерфейса, которому мы передаем реализацию HttpUpgradeHandler, в случае работы с Tomcat — это WsHttpUpgradeHandler. При инициализации экземпляра HttpUpgradeHandler создается EndPonit и регистрируется в WebSocketContainer. После этих настроек наша реализация WebSocketHandler готова принимать входящие сообщения, и с помощью WebSocketSession мы можем отправлять сообщения клиенту.
Большое спасибо за ваше внимание.
В следующих статьях мы рассмотрим работу резервного механизма с использованием SockJS и возможности субпротокола STOMP. Использованные источники: → Протокол вебсокетов → Весенний веб-сокет Теги: #java #spring framework #websocket #java
-
Экспресс-Анализ Качества Сайта
19 Oct, 24 -
Конец Эпохи, Меланхолия
19 Oct, 24 -
Любуясь Звездами
19 Oct, 24 -
Новый Нетбук Самсунг.
19 Oct, 24