Silk0vsky
Silk0vsky

Reputation: 1032

How to intercept websocket messages with spring cloud gateway

I'm running cloud gateway service in front of chat service which handles websocket connection. Do we have some convenient way to log interaction which happens between socket client & chat service on gateway side?

I've noticed that cloud gateway utilizes org.springframework.cloud.gateway.filter.WebsocketRoutingFilter to proxy websockets but not sure how to join its party & if it right place to go

Upvotes: 1

Views: 2829

Answers (2)

Yuan Ping
Yuan Ping

Reputation: 31

Spring Cloud Gateway is a powerful API gateway that provides a simple, yet effective way to route and filter incoming HTTP requests. While it's not specifically designed for WebSocket usage, it can be used to route WebSocket traffic by configuring custom filters.

To use filters to get WebSocket content in Spring Cloud Gateway, you can create a custom filter that extracts the WebSocket payload using the DataBuffer and DataBufferUtils classes. Here's an example:

@Component

public class WebSocketFilter implements GatewayFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return DataBufferUtils.join(exchange.getRequest().getBody())
            .flatMap(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                DataBufferUtils.release(dataBuffer);
                String payload = new String(bytes, StandardCharsets.UTF_8);
                // Do something with the WebSocket payload here
                return chain.filter(exchange);
            });
    }
}

In this example, the WebSocketFilter class implements the GatewayFilter interface and overrides its filter method. The method first uses DataBufferUtils.join to read the entire WebSocket payload into a single DataBuffer. Then, it extracts the bytes from the DataBuffer, converts them to a String using the UTF-8 charset, and finally applies some custom logic on the payload. Finally, the filter passes the exchange along the filter chain by invoking chain.filter(exchange).

To use the WebSocketFilter in your Spring Cloud Gateway configuration, you need to add it to the filter chain. Here's an example application.yml file that demonstrates how to do this:

spring:
 cloud:
   gateway:
     routes:
     - id: websocket_route
       uri: ws://localhost:8080/echo
       predicates:
       - Path=/websocket
       filters:
       - WebSocketFilter

In this example, we define a route with the ID websocket_route that forwards incoming WebSocket requests to the ws://localhost:8080/echo endpoint. We use a Path predicate to match incoming requests on the /websocket path, and we add our custom WebSocketFilter to the filter chain to extract the WebSocket payload.

Note that this example only extracts the payload from the WebSocket message, but you can modify the WebSocketFilter class to extract whatever information you need from the message.

Upvotes: 0

Silk0vsky
Silk0vsky

Reputation: 1032

At the moment I haven't found a way to attach own interceptors with instruments provided by framework. So I've decided to copy pasted WebsocketRoutingFilter implementation, with @Primary annotation & inject own logic this way.

Original WebsocketRoutingFilter creates instance of ProxyWebSocketHandler internally to handle socket session and there is a method handle which could be augmented.

Also be careful with DataBuffer which represents each message. It'controls the amount of data which had been already read. So I've decided to read messages this way:

private String readBufferedMessage(DataBuffer dataBuffer) {
    DataBuffer slice = dataBuffer.slice(0, dataBuffer.capacity());
    byte[] bytes = new byte[slice.readableByteCount()];
    slice.read(bytes);
    return new String(bytes, StandardCharsets.UTF_8);
}

Upvotes: 1

Related Questions