我查看了所有与此相关的问题,但我还没有找到适合我的解决方案。
我使用的是 retrofit 2.8.1
和 OkHttp 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.219.110.9:8085, proxy=DIRECT hostAddress=/34.219.110.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)
到目前为止,我已经尝试了一些事情
API在postman中工作正常,但当我从代码中尝试时却失败了。所以我尝试了postman发送的同样的头文件。还是没有结果。
一些观察。
EDIT 1:我打的服务器是由gunicorn20.0.4支持的,使用Flask。我没有访问服务器代码的权限。而且我怀疑发送收到的响应是否有一些垃圾字符导致错误。我不知道如何在被 retrofitokhttp 读取之前记录原始响应。
EDIT 2:
我用verbose运行Curl命令,得到的结果是:
< HTTP1.1 100 继续
- 服务器的回复为空
- 连接#0到主机xx.xxx.xxx.9的连接被完好无损的curl。(52) 来自服务器的回复为空
问题出在我所打的服务器上,它没有发送任何响应(完全没有。它没有发送任何响应(实际上什么都没有,没有标题,没有正文,什么都没有)。
所以在翻阅了stackoverflow上所有相关的答案,其他好的网站,并尝试了那么多我在问题本身中提到的解决方案后,并没有解决我的问题。
在仔细阅读了堆栈跟踪之后,我看到了以下一行。
okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:203)
客户端(我的代码)正在尝试读取Response头,这时出现了以下错误 java.io.EOFException: \n not found: limit=0 content=
被抛出。
这给了我一个提示,问题可能出在服务器上,而不是客户端。所以我想我应该用不同的客户端试试,看看是否能看到原始响应。
我想到的第一个工具是 Curl
(邮递员曾经给通用的 无法得到任何答复 而这并不是持续发生的)。) 我使用带有verbose选项的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)。
这个故事的寓意。 有时候你必须一个字一个字地读 stacktrace,即使它看起来不值得去看 :)
你会得到一个没有状态线的空回复。这就是问题所在。HTTP-request通常会返回一个状态行(例如. HTTP/1.1 200 OK\r\n
),其中包含状态代码,见 https:/www.ietf.orgrfcrfc2616.txt 第6.1章.这通常是一个服务器错误。