Hi I am trying to use ktor client websockets from ...
# ktor
s
Hi I am trying to use ktor client websockets from a spring boot application. My code looks like this:
Copy code
fun syncSubscribe() = runBlocking {
         subscribe()
}
suspend fun subscribe() {
         <http://logger.info|logger.info> { "Vault ws subscribed" }
         val eventType = EventType.write
         httpClient.wss(
             method = HttpMethod.Get,
             host = vaultHost,
             path = "/v1/sys/events/subscribe/kv-v1/$eventType?json=true",
             request = {
                 header("X-Vault-Token", vaultToken)
             }
         ) {
             while(true) {
                 val myDTO = receiveDeserialized<MyDTO>()
                 <http://logger.info|logger.info> { "Received: $myDTO" }
             }
         }
}
But I'm getting this error that I don't know how to resolve.
Copy code
Caused by: kotlinx.serialization.SerializationException: Serializer for class 'DefaultClientWebSocketSession' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
p.s. ktor_version = 2.3.3
a
Can you please share the response from
/v1/sys/events/subscribe/kv-v1/$eventType?json=true
?
The problem may be that the
/v1/sys/events/subscribe/kv-v1/$eventType?json=true
request returns a JSON response and the
ContentNegotiation
plugin tries to deserialize it
s
Does it make sense? Because my simple application with same code without spring boot works perfectly
Copy code
{
  "id": "22f8c382-e893-d676-7249-949ee8b81107",
  "source": "<https://vaultproject.io/>",
  "specversion": "1.0",
  "type": "*",
  "data": {
    "event": {
      "id": "22f8c382-e893-d676-7249-949ee8b81107",
      "metadata": {
        "path": "test"
      }
    },
    "event_type": "kv-v1/write",
    "plugin_info": {
      "mount_class": "secret",
      "mount_accessor": "kv_52920ec2",
      "mount_path": "kv/",
      "plugin": "kv"
    }
  },
  "datacontentype": "application/cloudevents",
  "time": "2023-08-07T10:24:55.6183514Z"
}
a
Please check what response is produced by the WebSockets endpoint. It should respond with 101 Switching Protocols status code.
s
So it is
a
Can you please share the response headers?
s
sure
Copy code
Response Headers:
Cache-Control: no-store
Connection: Upgrade
Sec-Websocket-Accept: PphdjXw2+sPxNVBO7rsQYyO04SU=
Sec-Websocket-Extensions: permessage-deflate; client_no_context_takeover; server_no_context_takeover
Strict-Transport-Security: max-age=31536000; includeSubDomains
Upgrade: websocket
a
Also, can you please share the HTTP client configuration?
I mean the instantiation of the Ktor's HTTP client with the plugins.
s
Copy code
val httpClient = HttpClient(CIO) {
        install(WebSockets) {
            contentConverter = KotlinxWebsocketSerializationConverter(Json)
        }
        install(ContentNegotiation) {
            json(Json {
                prettyPrint = true
                isLenient = true
                ignoreUnknownKeys = true
            })
        }
        defaultRequest {
            url {
                //protocol = URLProtocol.HTTPS
                host = vaultHost
            }
            header("X-Vault-Token", vaultToken)
        }
    }
Full log
a
As a workaround, please try to add the
DefaultClientWebSocketSession
class to the list of ignored types:
Copy code
install(ContentNegotiation) {
    ignoreType<DefaultClientWebSocketSession>()
    json(Json {
        prettyPrint = true
        isLenient = true
        ignoreUnknownKeys = true
    })
}
👍 1
s
@Aleksei Tirman [JB] Thank you very much, your answer helped me find the error. The error was that I was setting the same header twice as defaultRequest and directly when initializing the websocket connection. I expected that in this case header would be overwritten, but it is duplicated overwritten as an array. I am attaching a screenshot for a better understanding of the problem.