改造 POST java.io.IOException:由 java.io.EOFException 引起的连接上的流意外结束:\n 未找到:

Aru*_*wda 4 java gunicorn okhttp retrofit2

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

我正在使用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 );
}
Run Code Online (Sandbox Code Playgroud)

我构建了客户端,如下所示,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 );
}
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)

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

  1. 重试连接失败(真)
  2. .addHeader("连接","关闭")
  3. .header("接受编码", "身份")

邮递员的 API 工作正常,但当我尝试使用代码时却失败了。所以我尝试了邮递员发送的相同标题。仍然没有运气。

几个观察:

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

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

编辑2:

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

< HTTP/1.1 100 继续

  • 来自服务器的空回复
  • 与主机 xx.xxx.xxx.9 的连接 #0 保持完整卷曲:(52)来自服务器的空回复

Aru*_*wda 6

短篇故事

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

很长的故事

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

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

okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)
Run Code Online (Sandbox Code Playgroud)

客户端(我的代码)正在尝试读取 Response 标头,这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
Run Code Online (Sandbox Code Playgroud)

这证实了问题出在服务器上,而不是出在客户端(改造/http)上。

这个故事的寓意:有时你必须逐字阅读堆栈跟踪,即使它看起来不值得看:)