【问题标题】:Transfer Encoding chunked with okhttp only delivers full result使用 okhttp 分块的传输编码仅提供完整结果
【发布时间】:2019-04-10 00:22:05
【问题描述】:

我正在尝试对分块端点获得一些见解,因此计划逐块打印服务器发送给我的内容。我没有这样做,所以我写了一个测试,看看 OkHttp/Retrofit 是否按我的预期工作。

以下测试应该将一些块传送到控制台,但我得到的只是完整的响应。

我什至失去了让 OkHttp3 的 MockWebServer 向我发送块的东西。

我发现了这个改造问题条目,但答案对我来说有点模棱两可:Chunked Transfer Encoding Response

class ChunkTest {
    @Rule
    @JvmField
    val rule = RxImmediateSchedulerRule() // custom rule to run Rx synchronously

    @Test
    fun `test Chunked Response`() {
        val mockWebServer = MockWebServer()
        mockWebServer.enqueue(getMockChunkedResponse())

        val retrofit = Retrofit.Builder()
                .baseUrl(mockWebServer.url("/"))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .client(OkHttpClient.Builder().build())
                .build()
        val chunkedApi = retrofit.create(ChunkedApi::class.java)

        chunkedApi.getChunked()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe({
                    System.out.println(it.string())
                }, {
                    System.out.println(it.message)
                })

        mockWebServer.shutdown()
    }

    private fun getMockChunkedResponse(): MockResponse {
        val mockResponse = MockResponse()
        mockResponse.setHeader("Transfer-Encoding", "chunked")
        mockResponse.setChunkedBody("THIS IS A CHUNKED RESPONSE!", 5)
        return mockResponse
    }
}

interface ChunkedApi {
    @Streaming
    @GET("/")
    fun getChunked(): Flowable<ResponseBody>
}

测试控制台输出:

Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[49293] starting to accept connections
Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[49293] received request: GET / HTTP/1.1 and responded: HTTP/1.1 200 OK
THIS IS A CHUNKED RESPONSE!
Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$2 acceptConnections
INFO: MockWebServer[49293] done accepting connections: Socket closed

我预计会更像(每 5 个字节“剪切”一次正文):

Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$2 execute
INFO: MockWebServer[49293] starting to accept connections
Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$3 processOneRequest
INFO: MockWebServer[49293] received request: GET / HTTP/1.1 and responded: HTTP/1.1 200 OK
THIS
IS A 
CHUNKE
D RESPO
NSE!
Nov 06, 2018 4:08:15 PM okhttp3.mockwebserver.MockWebServer$2 acceptConnections
INFO: MockWebServer[49293] done accepting connections: Socket closed

【问题讨论】:

    标签: retrofit rx-java2 okhttp3 chunked


    【解决方案1】:

    OkHttp Mockserver 确实对数据进行了分块,但看起来 LoggingInterceptor 会等到整个块缓冲区已满,然后才会显示它。

    来自nice summary about HTTP streaming

    传输编码的使用:分块允许在单个请求或响应中进行流式传输。这意味着数据以分块方式传输,并且不会影响内容的表示.

    考虑到这一点,我们正在处理 1 个“请求/响应”,这意味着我们必须在获得整个响应之前进行块检索。然后将每个块推送到我们自己的缓冲区中,所有这些都在 OkHttp network interceptor 上。

    这里是说NetworkInterceptor的例子:

    class ChunksInterceptor: Interceptor {
    
        val Utf8Charset = Charset.forName ("UTF-8")
    
        override fun intercept (chain: Interceptor.Chain): Response {
            val originalResponse = chain.proceed (chain.request ())
            val responseBody = originalResponse.body ()
            val source = responseBody!!.source ()
    
            val buffer = Buffer () // We create our own Buffer
    
            // Returns true if there are no more bytes in this source
            while (!source.exhausted ()) {
                val readBytes = source.read (buffer, Long.MAX_VALUE) // We read the whole buffer
                val data = buffer.readString (Utf8Charset)
    
                println ("Read: $readBytes bytes")
                println ("Content: \n $data \n")
            }
    
            return originalResponse
        }
    }
    

    那我们当然要在 OkHttp 客户端上注册这个网络拦截器了。

    【讨论】:

      猜你喜欢
      • 2018-06-26
      • 1970-01-01
      • 2015-10-02
      • 2014-08-28
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2012-03-27
      • 1970-01-01
      相关资源
      最近更新 更多