通过WebSocket传输RSocket

默认情况下,RSocket通信是通过TCP套接字进行的。但在有些情况下,TCP协议并不是可行的方案。我们可以考虑以下两种情况:

  • 客户端是用JavaScript编写的,在用户的Web浏览器中运行;

  • 客户端必须穿过网关或防火墙边界才能到达服务器,而防火墙不允许通过任意端口进行通信。

此外,WebSocket本身缺乏对路由的支持,需要我们在应用层定义路由配置的细节。通过将RSocket构建在WebSocket之上,WebSocket能够从RSocket内置的路由支持中受益。

在这种情况下,RSocket可以通过WebSocket传输。WebSocket通信会使用HTTP实现,这是所有网络浏览器的主要通信手段,并且通常会被允许穿越防火墙。

要从TCP传输切换到WebSocket传输,我们只需要在服务器和客户端做一些小的改动。首先,由于WebSocket是通过HTTP传输的,需要确保服务器端的应用支持处理HTTP请求。简单地说,需要在项目的构建文件中添加以下WebFlux starter依赖(如果还没有添加):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

还需要通过设置 spring.rsocket.server.transport 属性来表明希望在服务器端配置中使用 WebSocket 进行传输。此外,需要通过设置spring.rsocket.server.mapping-path属性以配置RSocket通信时所使用的HTTP路径。在application.yml中,服务器的配置如下所示:

spring:
  rsocket:
    server:
      transport: websocket
      mapping-path: /rsocket

与通过特定端口进行通信的TCP传输不同,WebSocket传输会使用HTTP路径。因此,我们不需要像在TCP上运行的RSocket那样设置spring.rsocket.server.port属性。

以上是在服务器端为RSocket启用WebSocket传输要做的一些特殊工作,其他工作与TCP方式完全相同。

对于客户端,只需进行一个小改动。我们需要通过调用RSocketRequester.Builder上的websocket()方法来创建一个基于WebSocket的requester,以取代基于TCP的requester,如下所示:

RSocketRequester requester = requesterBuilder.websocket(
                    URI.create("ws://localhost:8080/rsocket"));

requester
    .route("greeting")
    .data("Hello RSocket!")
    .retrieveMono(String.class)
    .subscribe(response -> log.info("Got a response: {}", response));

这就是在WebSocket上传输RSocket所需的全部改动!

小结

  • RSocket是一个异步的二进制协议,提供了4种通信模式:请求-响应、请求-流、即发即忘和通道。

  • Spring通过控制器和带有@MessageHandler注解的处理器方法支持服务器端的RSocket。

  • RSocketRequester实现了客户端与RSocket服务器的通信。

  • 在客户端和服务器端,Spring的RSocket支持通过Reactor的Flux和Mono两种反应式类型实现完整的反应式通信。

  • RSocket通信默认使用TCP协议,但也可以通过WebSocket进行传输,从而突破防火墙的限制并兼容浏览器客户端。