【问题标题】:Okhttp java.net.ProtocolException: unexpected end of streamOkhttp java.net.ProtocolException:流意外结束
【发布时间】:2020-03-08 15:30:44
【问题描述】:

我目前正在开发 Android 应用程序,我正在使用 okttp3 发出一个简单的 GET 请求。我使用我的烧瓶应用程序作为 API 端点。 Android代码

 OkHttpClient client = new OkHttpClient();

        final Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {

                    String s = response.body().string();
                    System.out.println(s);

            }

            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {

                System.out.println(e.getMessage());
            }

        });

代码烧瓶

@app.route('/abc', methods=["GET"])
def abc():
    return jsonify({"test": "abc"})

当我使用 POSTMAN 发出请求时,我没有任何问题: postman get request 但是,当使用上面的 java 代码时,有时它可以工作,其他时候我得到以下错误

D/OkHttp: java.net.ProtocolException: unexpected end of stream
        at okhttp3.internal.http1.Http1ExchangeCodec$FixedLengthSource.read(Http1ExchangeCodec.kt:389)
        at okhttp3.internal.connection.Exchange$ResponseBodySource.read(Exchange.kt:276)
        at okio.Buffer.writeAll(Buffer.kt:1655)
        at okio.RealBufferedSource.readString(RealBufferedSource.kt:95)
        at okhttp3.ResponseBody.string(ResponseBody.kt:187)
        at com.example.teste.MainActivity$2.onResponse(MainActivity.java:83)
        at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:504)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
D/OkHttp:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

我尝试了多种解决方案,这些解决方案已在其他帖子中提出,例如:

OkHttpClient client = new OkHttpClient.Builder()
    .retryOnConnectionFailure(true)
    .build();

Request request = new Request.Builder()
                    .addHeader("Authorization", "Bearer " + apiToken)
                    .addHeader("content-type", "application/json")
                    .addHeader("Connection","close")
                    .url(uri)
                    .build();

但它们都不起作用。这里有什么问题?我曾尝试使用与其他虚拟 api 相同的代码发出请求,并且它始终有效。我的烧瓶 api 缺少什么?

错误发生在这里:

val read = super.read(sink, minOf(bytesRemaining, byteCount))
      if (read == -1L) {
        connection.noNewExchanges() // The server didn't supply the promised content length.
        val e = ProtocolException("unexpected end of stream")
        responseBodyComplete()
        throw e
      }

这与服务器提供的内容长度有关。我该如何解决这个问题?

【问题讨论】:

    标签: java python android flask okhttp


    【解决方案1】:

    如何为每个请求添加一个拦截器并添加Connection-Close 标头?如下。

    okHttpClient = new OkHttpClient.Builder()
            .addNetworkInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) throws IOException {
                    Request request = chain.request().newBuilder().addHeader("Connection", "close").build();
                    return chain.proceed(request);
                }
            })
            .build();
    

    HTTP/1.1 为发送者定义了“关闭”连接选项,以表示连接将在完成后关闭 回复。例如,

    连接:在请求或响应标头中关闭 字段表示不应该考虑连接 当前请求/响应之后的“持久”(第 8.1 节) 完成。

    不支持持久连接的 HTTP/1.1 应用程序必须 在每条消息中包含“关闭”连接选项。

    【讨论】:

      【解决方案2】:

      只有在我使用模拟器时才会发生异常。在设备上没有问题。

      【讨论】:

      • 这不是一个明确的答案。 OKHttp 库有问题。实际上发生了什么,模拟器上的java发出请求的速度比预期的要快,一旦它将一些数据读入缓冲区,库就会关闭连接,剩下的传入数据挂在中间,而服务器需要更多时间将整个数据写入输出缓冲区。现在这有时会在模拟器上工作,就像一个假/阳性结果一样。熟悉 C 套接字编程的人会非常清楚这种行为。
      猜你喜欢
      • 2020-01-23
      • 2015-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-12
      • 2022-08-24
      • 2018-05-05
      • 2019-01-20
      相关资源
      最近更新 更多