2

I have an okhttp3 (3.9.1) WebSocket instance and would like to view all it's network requests and responses. I tried to add some okhttp3.Interceptor instances to OkHttpClient instance before creating WebSocket on it but had no luck in viewing network activity. Here's sample code which demonstrates what I've tried to do:

package sample

import okhttp3.*
import java.io.IOException
import java.lang.Thread.sleep

fun main(args: Array<String>) {
    val listener = object : WebSocketListener() {
        override fun onMessage(webSocket: WebSocket?, text: String?) {
            println("Got server message: $text")
        }
    }

    val dummyInterceptor = Interceptor { chain ->
        val request = chain.request()
        val response = chain.proceed(request)
        println("Dummy interceptor fired!\n\nRequest: ${request.headers()}\nResponse: ${response.headers()}")
        return@Interceptor response
    }

    val dummyNetworkInterceptor = Interceptor { chain ->
        val request = chain.request()
        val response = chain.proceed(request)
        println("Dummy network interceptor fired!\n\nRequest: ${request.headers()}\nResponse: ${response.headers()}")
        return@Interceptor response
    }

    val okHttpClient = OkHttpClient.Builder()
            .addInterceptor(dummyInterceptor)
            .addNetworkInterceptor(dummyNetworkInterceptor)
            .build()

    val request = Request.Builder().url("ws://echo.websocket.org").build()

    val webSocket = okHttpClient.newWebSocket(request, listener)

    webSocket.send("Hello1!")
    webSocket.send("Hello2!")
    webSocket.send("Hello3!")

    sleep(2000) //Just for this sample to ensure all WS requests done
    println("\n\n\tSome network activity\n\n")

    okHttpClient.newCall(Request.Builder().get().url("http://echo.websocket.org").build()).enqueue(object : Callback {
        override fun onFailure(call: Call?, exc: IOException?) {
            println("OnFailure: ${exc?.message}")
        }

        override fun onResponse(call: Call?, response: Response?) {
            println("OnResponse: ${response?.headers()}")
        }
    })
}

I tried to dive into okhttp3 source code and didn't find any reason why any of my interceptors doesn't fire on WS requests but works perfectly for any OkHttpClient request.

Is it a bug in okhttp3 or am I doing something wrong or it's just not possible to monitor WS requests using okhttp3.Interceptor?

Jayson Minard
  • 84,842
  • 38
  • 184
  • 227

2 Answers2

2

WebSocket calls made with OkHttp don't use the interceptor chains that HTTP calls do, therefore you can't monitor them through interceptors.

I've faced this issue before myself, and so I looked at the source code and found the following then:

  • The regular HTTP calls go through the getResponseWithInterceptorChain() method in the RealCall class, which quite clearly starts the chained call of interceptors for each request.
  • The okhttp3.internal.ws package that includes the implementation of the WebSocket handling contains no code related to interceptors.

And really, interceptors catching WebSocket requests wouldn't really make sense in the first place. The Request that you can obtain in an interceptor represents an HTTP request, which WebSocket messages are not.

zsmb13
  • 85,752
  • 11
  • 221
  • 226
  • So...it just isn't possible to even log the requests and responses going through a websocket? – amitavk Jul 27 '19 at 10:57
  • @amitav13 you always can build a wrapper around your WS instance and log or intercept all requests and responses going through it at the _application_ level (i.e. except internal pings). My question was about intercepting such calls at the _network_ level using existing built-in `OkHttp` intercepters. – Rawnald Gregory Erickson Jul 28 '19 at 00:21
0

It isn't possible at this point, there's a feature request open for OkHttp but it isn't getting much traction: https://github.com/square/okhttp/issues/4192

amitavk
  • 1,196
  • 1
  • 12
  • 15