【问题标题】:Retrofit POST java.io.IOException: unexpected end of stream on Connection caused by java.io.EOFException: \n not found:Retrofit POST java.io.IOException: java.io.EOFException 导致 Connection 上的流意外结束: \n not found:
【发布时间】:2020-08-08 19:57:34
【问题描述】:

我已经解决了与此相关的所有问题,但我还没有找到适合我的解决方案。

我正在使用retrofit 2.8.1OkHttp 4.5.0

我的服务界面如下所示

public interface MlApiService
{
    @POST
    @Multipart
    Call<List<PreprocessedDocument>> postDocument( @Url String apiUrl, @Part MultipartBody.Part document,
    @Part ( "document_id") RequestBody documentId );
}

我构建客户端如下,requestTimeoutInSeconds 设置为 90 秒。

public void init()
{
    GsonBuilder gson = new GsonBuilder();
    gson.registerTypeAdapter( new TypeToken<List<PreprocessedDocument>>() {}.getType(), new CustomResponseDeserializer() );

    HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor();
    logInterceptor.setLevel( HttpLoggingInterceptor.Level.HEADERS );

    OkHttpClient client = new OkHttpClient.Builder().retryOnConnectionFailure( true ).addInterceptor( logInterceptor )
        .readTimeout( requestTimeoutInSeconds, TimeUnit.SECONDS ).build();
    //Dummy Base URL must be provided. otherwise client won't get initialized
    Retrofit retrofit = new Retrofit.Builder().baseUrl( "http://thisIsJustDummyUrlForTheSakeOfAddingBaseUrl.com/" )
        .client( client ).addConverterFactory( GsonConverterFactory.create( gson.setLenient().create() ) ).build();
    mlApiService = retrofit.create( MlApiService.class );
}

请求到达服务器,当服务器响应时,我收到以下错误:

Caused by: java.io.IOException: unexpected end of stream on Connection{34.XXX.XXX.9:8085, proxy=DIRECT hostAddress=/34.XXX.XXX.9:8085 cipherSuite=none protocol=http/1.1}
    at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)
    at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
Caused by: java.io.EOFException: \n not found: limit=0 content=…
    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:227)
    at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:211)
    at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:187)

到目前为止我尝试过的几件事

  1. retryOnConnectionFailure(true)
  2. .addHeader("Connection","close")
  3. .header("Accept-Encoding", "identity")

API 在邮递员中运行良好,但在我从代码中尝试时失败。所以我尝试了邮递员发送的相同标题。还是没有运气。

几个观察:

  1. 它有时会起作用。不会总是失败。(邮递员总是可以使用同一个文件)
  2. 它始终适用于其他文件(从不存在问题)。
  3. 请求到达服务器并处理请求而没有任何错误并且也响应。服务器完成处理并响应客户端后,我立即收到错误消息。

编辑 1: 我点击的服务器由 gunicorn/20.0.4 支持并使用 Flask。我无权访问服务器代码。而且我怀疑收到的响应是否包含一些导致错误的垃圾字符。在被改造/okhttp 读取之前,我不知道如何记录原始响应。

编辑 2:

我以详细的方式运行 Curl 命令,这就是我得到的。

  • 来自服务器的空回复
  • 与主机 xx.xxx.xxx.9 的连接 #0 保持不变 curl: (52) 来自服务器的空回复

【问题讨论】:

  • 如果它一直在 Postman 上工作,您最好的选择是将带有所有标头和正文的请求与您使用客户端生成的请求进行比较。您还可以查看文件内容是否有任何特殊或 Unicode 字符,因为您提到它是专门针对您收到此错误的文件的。有dos2unix类型的情况适用吗?
  • 这是一个pdf文件@somshivam
  • @somshivam 见观察#3。此外,如果我们看到堆栈跟踪 at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203) 它会显示 readResponseHeaders。这会留下线索吗?读取响应标头时出错?

标签: java retrofit2 gunicorn okhttp


【解决方案1】:

短篇小说

问题出在我正在访问的服务器上。它没有发送任何响应(实际上什么都没有。没有标题,没有正文,什么都没有)。

说来话长

因此,在查看了 stackoverflow 和其他优秀网站上的所有相关答案并尝试了我在问题本身中提到的这么多解决方案之后,它并没有解决我的问题。

仔细阅读堆栈跟踪后,我遇到了以下行。

okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)

客户端(我的代码)正在尝试读取响应标头,此时会抛出错误 java.io.EOFException: \n not found: limit=0 content=

这给了我一个提示,问题可能出在服务器而不是客户端。所以我想我应该尝试使用不同的客户端,看看我是否能看到原始响应。

我想到的第一个工具是Curl(邮递员过去常常给出通用的无法得到任何响应,但这种情况并没有持续发生)。我使用带有详细选项和繁荣的 curl 访问服务器!我收到以下回复:

curl -v --location --request POST 'http://XX.XXX.XXX.9:8085/psc/document_upload' --form 'document=@/home/user376/Downloads/test-1.pdf' --form 'document_id=22004494_ae7f_4998_a1d8_73249bda9905'
Note: Unnecessary use of -X or --request, POST is already inferred.
*   Trying XX.XXX.XXX.9...
* Connected to XX.XXX.XXX.9 (XX.XXX.XXX.9) port 8085 (#0)
> POST /psc/document_upload HTTP/1.1
> Host: XX.XXX.XXX.9:8085
> User-Agent: curl/7.49.0
> Accept: */*
> Content-Length: 4684053
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------a8446c7eedb10689
> 
< HTTP/1.1 100 Continue
* Empty reply from server
* Connection #0 to host XX.XXX.XXX.9 left intact
curl: (52) Empty reply from server

这确认问题出在服务器而不是客户端(Retrofit / http)。

故事的寓意:有时您必须逐字阅读堆栈跟踪,即使它似乎不值得查看:)

【讨论】:

    【解决方案2】:

    你得到一个没有状态行的空回复。这就是问题。 HTTP 请求通常返回一个状态行(例如HTTP/1.1 200 OK\r\n),其中包含状态代码,请参阅https://www.ietf.org/rfc/rfc2616.txt 第 6.1 章。 这通常是服务器错误。

    【讨论】:

      【解决方案3】:

      很可能有两件事同时发生。
      首先,该 url 包含一个不常用的端口,其次,您使用的 VPN 或代理不支持该端口。
      就个人而言,我遇到了同样的问题。
      我的服务器端口是 45860,我使用的是 pSiphon 反过滤 VPN。
      在这种情况下,我的邮递员仅在服务器的 relpy 是状态代码大于 0 的错误时才报告“连接挂断”。(当某些文本从服务器返回而没有错误代码时很好)
      然后我在我的服务器上将我的 Web 服务端口更改为 8080,哇,它工作了!虽然 psiphon vpn 已连接。
      因此,我的建议是,如果可以更改服务器端口,那就试试吧,或者检查是否有代理问题。也许您的 Postman 和 acual 应用不在同一台机器上。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-14
        • 1970-01-01
        • 2019-01-20
        • 2022-08-24
        • 1970-01-01
        • 2018-09-01
        • 1970-01-01
        相关资源
        最近更新 更多