В этом разделе кратко описаны опции, доступные в spring-test для приложений Spring MVC.

  • Фиктивные объекты Servlet API: Фиктивные реализации контрактов Servlet API для модульного тестирования контроллеров, фильтров и других веб-компонентов.

  • TestContext Framework: Поддержка загрузки конфигурации Spring в тестах JUnit и TestNG, включая эффективное кэширование загруженной конфигурации в тестовых методах и поддержку загрузки WebApplicationContext с MockServletContext.

  • Spring MVC Test: Фреймворк, также известный как MockMvc, предназначенный для тестирования аннотированных контроллеров через DispatcherServlet (то есть поддерживающий аннотации), в комплекте с инфраструктурой Spring MVC, но без HTTP-сервера.

  • REST на стороне клиента: spring-test предоставляет MockRestServiceServer, который можно использовать как фиктивный сервер для тестирования кода на стороне клиента, который на внутреннем уровне использует RestTemplate.

  • WebTestClient: Создан для тестирования приложений WebFlux, но может также использоваться для сквозного интеграционного тестирования на любом сервере через HTTP-соединение. Это неблокирующий, реактивный клиент, который хорошо подходит для тестирования в сценариях асинхронной работы и потоковой передачи.

Веб-сокеты протокола WebSocket

Эта часть справочной документации охватывает поддержку стека сервлетов, обмен сообщениями через WebSocket, включающий необработанные взаимодействия WebSocket, эмуляцию WebSocket через SockJS и обмен сообщениями "публикация-подписка" через STOMP как субпротокол поверх WebSocket.

Введение в протокол WebSocket

Протокол WebSocket, RFC 6455, предусматривает стандартизированный способ установления полнодуплексного двустороннего канала связи между клиентом и сервером поверх одного TCP-соединения. Это отличный от HTTP протокол TCP, но он предназначен для работы поверх HTTP, использует порты 80 и 443 и позволяет повторно использовать существующие правила брандмауэра.

Взаимодействие WebSocket начинается с HTTP-запроса, который использует HTTP-заголовок Upgrade для обновления или, в данном случае, для перехода на протокол WebSocket. В следующем примере показано такое взаимодействие:

GET /spring-websocket-portfolio/portfolio HTTP/1.1
Host: localhost:8080
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg==
Sec-WebSocket-Protocol: v10.stomp, v11.stomp
Sec-WebSocket-Version: 13
Origin: http://localhost:8080
  1. Заголовок Upgrade.
  2. Использование соединения Upgrade.

Вместо обычного кода состояния 200 сервер с поддержкой WebSocket выдает сообщение, похожее на следующее:

HTTP/1.1 101 Switching Protocols 
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0=
Sec-WebSocket-Protocol: v10.stomp
  1. Переключатель протоколов

После успешного подтверждения установления связи сокет TCP, лежащий в основе запроса на обновление HTTP, остается открытым, чтобы клиент и сервер могли продолжать отправлять и получать сообщения.

Полное введение в работу веб-сокетов протокола WebSocket выходит за рамки этого документа. См. "RFC 6455", главу, посвященную WebSocket в HTML5, или любое из многочисленных описаний и учебных пособий в Интернете.

Обратите внимание, что если сервер WebSocket работает за веб-сервером (например, nginx), то, скорее всего, потребуется сконфигурировать его на передачу запросов на обновление WebSocket серверу. Аналогичным образом, если приложение работает в облачной среде, проверьте инструкции поставщика облачных услуг, касающиеся поддержки WebSocket.

HTTP против WebSocket

Несмотря на то, что протокол WebSocket разработан как HTTP-совместимый и исходит из HTTP-запроса, важно понимать, что эти два протокола влекут за собой совершенно разные архитектуры и модели программирования приложений.

В HTTP и REST приложение моделируется как множество URL-адресов. Чтобы взаимодействовать с приложением, клиенты обращаются к этим URL-адресам в стиле "запрос-ответ". Серверы направляют запросы к соответствующему обработчику на основе URL-адреса, метода и заголовков HTTP.

Напротив, в веб-сокетах протокола WebSocket для первоначального подключения обычно используется только один URL-адрес. Впоследствии все сообщения приложения передаются по этому же TCP-соединению. Это указывает на совершенно иную асинхронную, управляемую событиями архитектуру обмена сообщениями.

WebSocket также является низкоуровневым транспортным протоколом, который, в отличие от HTTP, не предписывает никакой семантики содержимому сообщений. Это означает, что не существует способа маршрутизации или обработки сообщения, пока между клиентом и сервером не будет согласована семантика сообщения.

Клиенты и серверы на WebSocket могут согласовать использование протокола обмена сообщениями более высокого уровня (например, STOMP) с помощью заголовка Sec-WebSocket-Protocol в HTTP-запросе подтверждения установления связи. В отсутствие этого им нужно придумать свои собственные соглашения.

Когда следует использовать веб-сокеты протокола WebSocket?

Веб-сокеты протокола WebSocket могут сделать веб-страницу динамичной и интерактивной. Однако во многих случаях сочетание Ajax и HTTP-потока или длинного поллинга (опроса) может быть простым и эффективным решением.

Например, новости, почта и социальные ленты должны обновляться динамически, но вполне допустимо делать это раз в несколько минут. С другой стороны, приложения для совместной работы, игры и финансовые приложения должны чаще работать в реальном времени.

Сама по себе задержка не является решающим фактором. Если объем сообщений относительно невелик (например, при мониторинге сетевых сбоев), эффективным решением может стать потоковая передача или поллинг по HTTP-протоколу. Именно сочетание низкой задержки, высокой частоты и большого объема является наилучшим аргументом в пользу использования WebSocket.

Помните также, что в Интернете ограничительные прокси-серверы, которые находятся вне вашего контроля, могут препятствовать взаимодействию WebSocket, либо потому что они не настроены на передачу заголовка Upgrade, либо потому что они закрывают долговременные соединения, которые, как представляется, неактивны. Это означает, что использование WebSocket для внутренних приложений в рамках брандмауэра является более простым решением, чем для публичных приложений.