WebSocket
Протоколы — это один из способов, с помощью которых приложение обрабатывает сообщения в реальном времени. Наиболее распространенными альтернативами являются длительные опросы и события, отправленные сервером. У каждого из этих решений есть свои плюсы и минусы. В этой статье я покажу вам, как использоватьSpring Boot
выполнитьWebSocket
. Я расскажу о настройке на стороне сервера и на стороне клиента, используяWebSocket
по соглашениюSTOMP
общаться друг с другом.
Серверная часть будет полностью написана на Java. Однако, что касается клиента, я покажуJava
иJavaScript(SockJS)
письменные фрагменты, потому что обычно,WebSocket
Клиент встроен в интерфейсное приложение. Примеры кода продемонстрируют, как использоватьpub-sub
Моделирует, как рассылать сообщения нескольким пользователям и как отправлять сообщения только одному пользователю. В другой части этой статьи я кратко расскажу о вопросах безопасности WebSocket и о том, как гарантировать, что даже если среда не поддерживаетWebSocket
соглашение, основанное наWebSocket
решение тоже работает.
Уведомление,WebSocket
Тема безопасности здесь затронута лишь вкратце, так как это очень сложный вопрос, который можно было бы написать в отдельной статье. По этой причине, а также в последнем разделе моей статьиWebSocket in production?
Учитывая факторы, упомянутые в разделе , я рекомендую изменять параметры безопасности в рабочей среде до тех пор, пока она не будет готова и не будут приняты меры безопасности.
1. WebSocket и протокол STOMP
WebSocket
Протоколы обеспечивают двустороннюю связь между приложениями. Важно знатьHTTP
Используется только для первоначального рукопожатия. После первого рукопожатияHTTP
Соединение будет обновлено доWebSocket
новый подержанныйTCP/IP
соединять.
WebSocket
Протокол — это довольно низкоуровневый протокол. Он определяет, как преобразовать поток байтов в кадры. Фреймы могут содержать текстовые или бинарные сообщения. Поскольку само сообщение не предоставляет никакой другой информации о том, как его маршрутизировать или обрабатывать, трудно реализовать более сложные приложения без написания дополнительного кода. К счастью,WebSocket
Спецификация позволяет использовать подпротоколы на более высоком уровне приложений.STOMP
является одним из них, поSpring Framework
служба поддержки.
STOMP
это простой протокол обмена текстовыми сообщениями, первоначально предназначенный дляRuby
,Python
иPerl
и другие языки сценариев для подключения к брокерам сообщений корпоративного уровня. так какSTOMP
, чтобы клиенты и агенты, разработанные на разных языках, могли отправлять и получать сообщения друг от друга.WebSocket
Соглашение иногда называютWeb TCP
. В этом виде толчка,STOMP
называетсяWeb HTTP
. Он определяет некоторое отображение наWebSocket
тип кадра кадра, например.CONNECT
,SUBSCRIBE
,UNSUBSCRIBE
,ACK
илиSEND
. С одной стороны, эти команды очень удобны для управления коммуникацией, а с другой — позволяют реализовать решения с более сложными функциями, такими как подтверждение сообщений.
2. Сервер: Spring Boot и WebSocket
чтобы построитьWebSocket
Серверная часть, мы будем использоватьSpring Boot
Framework, который ускоряет разработку автономных программ и веб-приложений на Java.Spring Boot
Включаютspring-WebSocket
модуль, который связан сJava WebSocket API
Соответствует стандартам (JSR-356).
использоватьSpring Boot
выполнитьWebSocket
Серверная часть не очень сложная задача и состоит всего из нескольких шагов, которые мы пройдем один за другим.
*Шаг 1:* Сначала добавьте зависимости библиотеки WebSocket.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
Если вы планируете использоватьJSON
сообщение о передаче формата, вам также может понадобиться включитьGSON
илиJackson
зависимости. Вам также может понадобиться структура безопасности, такая какSpring Security
.
*Шаг 2:* Затем вы можете настроитьSpring
включитьWebSocket
иSTOMP
обмен сообщениями.
Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry
registry) {
registry.addEndpoint("/mywebsockets")
.setAllowedOrigins("mydomain.com").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config){
config.enableSimpleBroker("/topic/", "/queue/");
config.setApplicationDestinationPrefixes("/app");
}
}
configureMessageBroker
Делайте в основном две вещи:
- Создает брокер сообщений в памяти, который содержит одно или несколько мест назначения для отправки и получения сообщений. В приведенном выше примере определены два префикса адреса назначения:
topic
иqueue
. Они следуют соглашению о том, что в рамках модели pub-subtopic
Адрес назначения для сообщений с префиксом, которые должны быть доставлены всем подписавшимся клиентам. С другой стороны, адрес назначения личных сообщений обычно начинается сqueue
как префикс. - определить префикс
app
, который используется для фильтрации целевых адресов, находящихся вController
в одеяле@MessageMapping
Модифицированный метод обработки.
Возвращаясь к приведенному выше фрагменту — вероятно, вы заметили, что методwithSockJS()
вызов - это позволяетSockJS
Резервный вариант. Короче говоря, даже если интернет-браузер не поддерживаетWebSocket
протокола, это также позволит нашимWebSockets
Работа. Я рассмотрю эту тему более подробно.
Еще одно уточнение - почему мы звоним на конечную точкуsetAllowedOrigins()
метод.一般是必需的,因为WebSocket
иSockJS
Поведение по умолчанию — принимать только запросы от одного и того же источника. Поэтому, если клиент и сервер находятся в разных доменах, необходимо вызвать этот метод, чтобы разрешить связь между ними.
*Шаг 3:* Внедрите контроллер, который обрабатывает запросы пользователей Он будет транслировать полученное сообщение всем пользователям, подписавшимся на определенную тему.
Это отправить сообщение на целевой адрес/topic/news
метод примера.
@MessageMapping("/news")
@SendTo("/topic/news")
public void broadcastNews(@Payload String message) {
return message;
}
также можно использоватьSimpMessagingTemplate
вместо аннотаций@SendTo
, вы можете Autowired внутри контроллера.
@MessageMapping("/news")
public void broadcastNews(@Payload String message) {
this.simpMessagingTemplate.convertAndSend("/topic/news", message)
}
На более поздних этапах может потребоваться добавить некоторые дополнительные классы для защиты конечной точки, например.Spring Security
в рамкеResourceServerConfigurerAdapter
илиWebSecurityConfigurerAdapter
. Кроме того, часто бывает полезно реализовать модель сообщений таким образом, чтобыJSON
могут быть сопоставлены с объектами.
3. Создание клиента WebSocket
Реализация клиента — более простая задача.
*Шаг 1: *СборкаSpring STOMP
клиент
@Autowired
private WebSocketStompClient stompClient;
Шаг 2:открытое соединение
StompSessionHandler sessionHandler = new CustmStompSessionHandler();
StompSession stompSession = stompClient.connect(loggerServerQueueUrl,
sessionHandler).get();
После завершения этой операции сообщение может быть отправлено получателю. Сообщение будет отправлено всем подписавшимся на тему пользователям.
stompSession.send("topic/greetings", "Hello new user");
Следующие методы также могут подписаться на сообщения
session.subscribe("topic/greetings", this);
@Override
public void handleFrame(StompHeaders headers, Object payload) {
Message msg = (Message) payload;
logger.info("Received : " + msg.getText()+ " from : " +
msg.getFrom());
}
Иногда необходимо отправить сообщение конкретному пользователю (например, при реализации чата). Затем клиентская и серверная стороны должны использовать отдельные адреса назначения, предназначенные для этого частного сеанса. Имя адреса назначения может быть создано путем добавления уникального идентификатора к общему адресу, например./queue/chat-user123
.HTTP
сеанс илиSTOMP
Идентификатор сеанса, используемый для этой цели.
Spring
Облегчает отправку личных сообщений. нам просто нужно использовать@SendToUser
ПримечанияController
Методы. Затем адрес назначения будет указанUserDestinationMessageHandler
обработка, основанная на идентификаторе сеанса. На стороне клиента, когда клиент подписывается на/user
При наличии префикса адреса назначения этот адрес назначения будет преобразован в адрес назначения, уникальный для этого пользователя. На стороне сервера, по желанию пользователяPrincipal
Разрешить адрес назначения пользователя.
использование на стороне сервера@SendToUser
Аннотированный пример кода:
@MessageMapping("/greetings")
@SendToUser("/queue/greetings")
public String reply(@Payload String message,
Principal user) {
return "Hello " + message;
}
или вы можете использоватьSimpMessagingTemplate
:
String username = ...
this.simpMessagingTemplate.convertAndSendToUser();
username, "/queue/greetings", "Hello " + username);
Теперь давайте посмотрим, как реализовать метод, который может получать личные сообщения.JavaScript(SockJS)
Клиент, клиент может получить сообщение в приведенном выше примере отправки кода Java. Стоит отметить, чтоWebSockets
даHTML5
часть спецификации и поддерживается большинством современных браузеров (начиная с версии 10,Internet Explorer
поддерживать их).
function connect() {
var socket = new SockJS('/greetings');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
stompClient.subscribe('/user/queue/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body).name);
});
});
}
function sendName() {
stompClient.send("/app/greetings", {}, $("#name").val());
}
Вы могли заметить, что для получения личных сообщений клиентам необходимо подписаться с префиксом/user
адрес назначения/queue/greetings
. Ему не нужно беспокоиться о каких-либо уникальных идентификаторах. Однако, прежде чем клиент сможет войти в приложение, серверная сторона должна инициализироватьPrincipal
объект.
4. Безопасность веб-сокетов
многиеWeb
Использование приложения основано наcookie
аутентификацию, например, мы можем использоватьSpring Security
Ограничьте вошедшим в систему пользователям доступ к определенным страницам или ограничениям контроллера. Затем безопасность пользовательского контекста поддерживается с помощью сеанса HTTP на основе файлов cookie, который позже связывается сWebSocket
илиSockJS
Связанная сессия.WebSocket
Конечные точки могут быть защищены, как и любой другой запрос, например, вSpring
WebSecurityConfigurerAdapter
реализация в.
в настоящее время,Web
приложения обычно используютREST API
В качестве бэкенда используйтеOAuth/JWT
Токен для аутентификации и авторизации пользователя.WebSocket
Протокол не описывает сервер вHTTP
Как клиент аутентифицируется во время рукопожатия. На самом деле стандартHTTP
заголовки (например, Authorization) используются для этой цели. К сожалению, не всеSTOMP
Все клиенты это поддерживают.Spring
изSTOMP
Клиент позволяет установить заголовок, чтобы пожать руку:
WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders();
handshakeHeaders.add(principalRequestHeader, principalRequestValue);
ноSockJS
Клиент JavaScript не поддерживает использованиеSockJS
Запрос отправляет заголовок Authorization (Авторизация). Однако он позволяет отправлять параметры запроса, которые можно использовать для передачи токенов. Этот подход требует написания пользовательского кода на стороне сервера, который будет считывать токен из параметров запроса и проверять его. Особенно важно убедиться, что токен не регистрируется вместе с запросом (или что журналы хорошо защищены), так как это может привести к серьезным нарушениям безопасности.
5. Резервные варианты SockJS
иWebSocket
Интеграция не всегда может быть так хороша, как должна быть. Некоторые браузеры (например, IE 9) не поддерживаютWebSocket
. Более того, ограничительные прокси-серверы могут сделать невозможным обновление HTTP или обрезать соединения, которые были открыты слишком долго. В этом случае на помощь приходит SockJS.
SockJS
Существует три основных категории трансферов:WebSocket
,HTTP Streaming
иHTTP Long Polling
. сообщение отSockJS
ОтправитьGET
/info
Начните с получения базовой информации с сервера.SockJS
Какой транспорт использовать, зависит от ответа. Первый вариантWebSocket
. Если не поддерживается, используйте, если возможноStreaming
. еслиStreaming
недоступен, выберите в качестве метода передачи опрос.
6. Используйте веб-сокеты в производстве
Хотя эта установка работает, она не «оптимальна».Spring Boot
позволяет использовать любойSTOMP
Полная система обмена сообщениями для протокола (например, ActiveMQ, RabbitMQ) и многое другое может поддерживаться внешними брокерами.STOMP
Действия (например, подтверждение, аренда) вместо простого прокси, который мы используем.STOMP Over WebSocket
предоставить оWebSocket
иSTOMP
информация о договоре. он перечисляет обработкуSTOMP
Система обмена сообщениями протокола может быть лучшим решением, используемым в производстве. Особенно из-за большого количества запросов агент сообщений нуждается в кластере (простой агент сообщений Spring не подходит для кластера). Тогда не надоWebSocketConfig
Включите Simple Proxy в , вместо этого вам нужно включитьStomp
Ретранслятор брокера, который пересылает сообщения внешним брокерам сообщений и обратно. В целом, внешние брокеры сообщений могут помочь вам создать более масштабируемые и надежные решения.
Оригинальная ссылка:woohoo.topthem.com/java/stomp-…
Автор: Томаш Домбровский
Переводчик: Эмма
Рекомендуется обратить внимание на паблик аккаунт: большой парень вне банка
Ежедневно публикуйте отличные зарубежные статьи с техническими переводами, которые вдохновляют на то, чтобы помочь отечественным разработчикам стать лучше!