WebSocket API
Spring Framework は、WebSocket メッセージを処理するクライアント側およびサーバー側のアプリケーションを作成するために使用できる WebSocket API を提供します。
WebSocketHandler
WebSocket サーバーの作成は、WebSocketHandler
を実装するのと同じくらい簡単で、おそらくは TextWebSocketHandler
または BinaryWebSocketHandler
のいずれかを継承します。次の例では、TextWebSocketHandler
を使用しています。
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// ...
}
}
次の例に示すように、専用の WebSocket Java 構成と、前述の WebSocket ハンドラーを特定の URL にマッピングするための XML 名前空間のサポートがあります。
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
次の例は、前述の例に相当する XML 構成を示しています。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:handlers>
<websocket:mapping path="/myHandler" handler="myHandler"/>
</websocket:handlers>
<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
</beans>
上記の例は Spring MVC アプリケーションで使用するためのものであり、DispatcherServlet
の構成に含める必要があります。ただし、Spring の WebSocket サポートは Spring MVC に依存しません。WebSocketHttpRequestHandler
(Javadoc) の助けを借りて、WebSocketHandler
を他の HTTP サービス環境に統合するのは比較的簡単です。
WebSocketHandler
API を直接または間接的に使用する場合、たとえば基礎となる標準 WebSocket セッション(JSR-356)は同時送信を許可しないため、STOMP メッセージングを介して、アプリケーションはメッセージの送信を同期する必要があります。1 つのオプションは、WebSocketSession
を ConcurrentWebSocketSessionDecorator
(Javadoc) でラップすることです。
WebSocket ハンドシェイク
最初の HTTP WebSocket ハンドシェイクリクエストをカスタマイズする最も簡単な方法は、ハンドシェイクの「前」と「後」のメソッドを公開する HandshakeInterceptor
を使用することです。このようなインターセプターを使用して、ハンドシェイクを除外したり、WebSocketSession
で属性を使用可能にしたりできます。次の例では、組み込みインターセプターを使用して、HTTP セッション属性を WebSocket セッションに渡します。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(new MyHandler(), "/myHandler")
.addInterceptors(new HttpSessionHandshakeInterceptor());
}
}
次の例は、前述の例に相当する XML 構成を示しています。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:handlers>
<websocket:mapping path="/myHandler" handler="myHandler"/>
<websocket:handshake-interceptors>
<bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/>
</websocket:handshake-interceptors>
</websocket:handlers>
<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
</beans>
より高度なオプションは、WebSocket ハンドシェイクのステップを実行する DefaultHandshakeHandler
を継承することです。これには、クライアントの発信元の検証、サブプロトコルのネゴシエーション、その他の詳細が含まれます。アプリケーションは、WebSocket サーバーエンジンとまだサポートされていないバージョンに適応するためにカスタム RequestUpgradeStrategy
を構成する必要がある場合、このオプションを使用する必要があります(このテーマの詳細については、デプロイを参照してください)。Java 構成と XML 名前空間の両方により、カスタム HandshakeHandler
を構成できます。
Spring は、WebSocketHandler を追加の動作で装飾するために使用できる WebSocketHandlerDecorator 基本クラスを提供します。WebSocket Java 構成または XML 名前空間を使用する場合、デフォルトでロギングおよび例外処理の実装が提供および追加されます。ExceptionWebSocketHandlerDecorator は、WebSocketHandler メソッドから発生するすべてのキャッチされない例外をキャッチし、サーバーエラーを示すステータス 1011 の WebSocket セッションを閉じます。 |
デプロイ
Spring WebSocket API は、DispatcherServlet
が HTTP WebSocket ハンドシェイクと他の HTTP リクエストの両方に対応する Spring MVC アプリケーションに簡単に統合できます。WebSocketHttpRequestHandler
を呼び出すことで、他の HTTP 処理シナリオに簡単に統合することもできます。これは便利で分かりやすいです。ただし、JSR-356 ランタイムに関しては特別な考慮事項が適用されます。
Jakarta WebSocket API (JSR-356) は、2 つの デプロイメカニズムを提供します。1 つ目は、起動時のサーブレットコンテナークラスパススキャン (Servlet 3 機能) です。もう 1 つは、サーブレットコンテナーの初期化時に使用する登録 API です。これらのメカニズムのどちらも、WebSocket ハンドシェイクや Spring MVC の DispatcherServlet
などの他のすべての HTTP リクエストを含む、すべての HTTP 処理に単一の「フロントコントローラー」を使用することを可能にします。
これは、JSR-356 ランタイムで実行されている場合でも、Spring の WebSocket がサーバー固有の RequestUpgradeStrategy
実装でアドレスをサポートするという JSR-356 の重大な制限です。このような戦略は現在、Tomcat、Jetty、GlassFish、WebLogic、WebSphere、Undertow (および WildFly) に存在します。Jakarta WebSocket 2.1 の時点で、Spring が Tomcat 10.1 や Jetty 12 などの Jakarta EE 10 ベースの Web コンテナーで選択する標準のリクエストアップグレード戦略が利用可能です。
2 番目の考慮事項は、JSR-356 をサポートするサーブレットコンテナーが ServletContainerInitializer
(SCI)スキャンを実行すると予想されることです。これにより、アプリケーションの起動が遅くなる場合があります。JSR-356 をサポートするサーブレットコンテナーバージョンへのアップグレード後に重大な影響が観察された場合、次の例のように、web.xml
の <absolute-ordering />
要素を使用して、Web フラグメント(および SCI スキャン)を選択的に有効または無効にできます。ショー:
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<absolute-ordering/>
</web-app>
次に、Servlet 3 Java 初期化 API のサポートを提供する Spring 独自の SpringServletContainerInitializer
など、名前で Web フラグメントを選択的に有効にできます。次の例は、その方法を示しています。
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<absolute-ordering>
<name>spring_web</name>
</absolute-ordering>
</web-app>
サーバーの構成
入力メッセージバッファサイズ、アイドルタイムアウトなど、基盤となる WebSocket サーバーを構成できます。
Jakarta WebSocket サーバーの場合は、Java 構成に ServletServerContainerFactoryBean
を追加できます。例:
@Bean
public ServletServerContainerFactoryBean createWebSocketContainer() {
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
container.setMaxTextMessageBufferSize(8192);
container.setMaxBinaryMessageBufferSize(8192);
return container;
}
または、XML 設定に次のようにします。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<bean class="org.springframework...ServletServerContainerFactoryBean">
<property name="maxTextMessageBufferSize" value="8192"/>
<property name="maxBinaryMessageBufferSize" value="8192"/>
</bean>
</beans>
クライアント Jakarta WebSocket 構成の場合は、Java 構成では ContainerProvider.getWebSocketContainer() を使用するか、XML では WebSocketContainerFactoryBean を使用します。 |
Jetty の場合、Consumer
コールバックを指定して WebSocket サーバーを構成できます。
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(echoWebSocketHandler(), "/echo").setHandshakeHandler(handshakeHandler());
}
@Bean
public DefaultHandshakeHandler handshakeHandler() {
JettyRequestUpgradeStrategy strategy = new JettyRequestUpgradeStrategy();
strategy.addWebSocketConfigurer(configurable -> {
policy.setInputBufferSize(8192);
policy.setIdleTimeout(600000);
});
return new DefaultHandshakeHandler(strategy);
}
}
WebSocket 経由で STOMP を使用する場合は、STOMP WebSocket トランスポートプロパティも構成する必要があります。 |
許可されたオリジン
Spring Framework 4.1.5 以降、WebSocket および SockJS のデフォルトの動作では、同一生成元のリクエストのみを受け入れます。すべてまたは指定されたオリジンのリストを許可することもできます。このチェックは、主にブラウザークライアント用に設計されています。他の型のクライアントが Origin
ヘッダー値を変更することを妨げるものはありません(詳細については、RFC 6454: Web Origin のコンセプト [IETF] (英語) を参照してください)。
3 つの可能な動作は次のとおりです。
同一オリジンリクエストのみを許可(デフォルト): このモードでは、SockJS が有効になっている場合、リクエストのオリジンのチェックが許可されないため、Iframe HTTP レスポンスヘッダー
X-Frame-Options
がSAMEORIGIN
に設定され、JSONP トランスポートが無効になります。そのため、このモードが有効になっている場合、IE6 および IE7 はサポートされません。指定されたオリジンのリストを許可: 許可された各オリジンは
http://
またはhttps://
で始まる必要があります。このモードでは、SockJS を有効にすると、IFrame トランスポートが無効になります。そのため、このモードが有効になっている場合、IE6 から IE9 はサポートされません。すべてのオリジンを許可: このモードを有効にするには、許可された起点値として
*
を提供する必要があります。このモードでは、すべてのトランスポートが利用可能です。
次の例に示すように、WebSocket と SockJS が許可するオリジンを設定できます。
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("https://mydomain.com");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
次の例は、前述の例に相当する XML 構成を示しています。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
https://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:handlers allowed-origins="https://mydomain.com">
<websocket:mapping path="/myHandler" handler="myHandler" />
</websocket:handlers>
<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
</beans>