unexpected end of stream on okhttp3.Address 和 Caused by: java.io.EOFException: \n not found: size=0

今天遇到一个OkHttpClient的坑,报错信息如下:

[20200320 10:47:10.553] | [ERROR] | [localhost] | [http-nio-28080-exec-22] | [c.u.] | [unexpected end of stream on okhttp3.Address@fe4f10d5] |
`java.io.IOException: unexpected end of stream on okhttp3.Address@fe4f10d5`
	at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:199)
	at okhttp3.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:125)
	at okhttp3.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:775)
	at okhttp3.internal.http.HttpEngine.access$200(HttpEngine.java:86)
	at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:760)
	at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:733)
。。。。。。。。。。。。。。。。。。。。。。。。。。。org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:748)
`Caused by: java.io.EOFException: \n not found: size=0 content=`
	at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:215)
	at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:184)
	... 49 common frames omitted

排查如下:

查看了一下源码:

//RetryAndFollowUpInterceptor.java
   @NotNull
   public Response intercept(@NotNull Chain chain) throws IOException {
           Intrinsics.checkParameterIsNotNull(chain, "chain");
      Request request = chain.request();
      RealInterceptorChain realChain = (RealInterceptorChain)chain;
      Transmitter transmitter = realChain.transmitter();
      int followUpCount = 0;
      Response priorResponse = (Response)null;

      while(true) {
        //....省略
       try {
                     var16 = true;
                     response = realChain.proceed(request, transmitter, (Exchange)null);
                     var8 = true;
                     var16 = false;
                     break label186;
                  } catch (RouteException var17) {
                     if (!this.recover(var17.getLastConnectException(), transmitter, 							false, request)) {
                        throw (Throwable)var17.getFirstConnectException();
                     }
            //....省略
     }
   }       
       
       private final boolean recover(IOException e, Transmitter transmitter, boolean requestSendStarted, Request userRequest) {
          if (!this.client.retryOnConnectionFailure()) {
             return false;
          } else if (requestSendStarted && this.requestIsOneShot(e, userRequest)) {
             return false;
          } else if (!this.isRecoverable(e, requestSendStarted)) {
             return false;
          } else {
             return transmitter.canRetry();
          }
   }

从源码中可以看出如果retryOnConnectionFailure设置的为false的话,recover()方法将返回false,intercept中将抛出异常。
如果是true的话,将继续继续执行realChain.proceed()方法。

当执行realChain.proceed() ,将事件继续分发给各个拦截器,最终执行到 Http1ExchangeCodec#readResponseHeaders 方法。

 @Nullable
   public Builder readResponseHeaders(boolean expectContinue) {
      boolean var2 = this.state == 1 || this.state == 3;
      boolean var3 = false;
      boolean var4 = false;
      if (!var2) {
         int var5 = false;
         String var10 = "state: " + this.state;
         throw (Throwable)(new IllegalStateException(var10.toString()));
      } else {
         try {
            StatusLine statusLine = StatusLine.Companion.parse(this.readHeaderLine());
            Builder responseBuilder = (new Builder()).protocol(statusLine.protocol).code(statusLine.code).message(statusLine.message).headers(this.readHeaders());
            //.............省略
         } catch (EOFException var6) {
           //............省略

            String address = var14;
             //此处的异常便是上文出现的unexpected end of stream on okhttp3.Address@fe4f10d5
            throw (Throwable)(new IOException("unexpected end of stream on " + address, (Throwable)var6));
         }
      }
   }

 private final String readHeaderLine() {
      //RealBufferedSource#readUtf8LineStrict方法
      String line = this.source.readUtf8LineStrict(this.headerLimit);
      this.headerLimit -= (long)line.length();
      return line;
   }

继续查看RealBufferedSource.java文件。

 //RealBufferedSource.java
// 此时如果server端已经closed了,那么取到的buffer 为 null 将EOF异常向上抛出  
@Override public String readUtf8LineStrict() throws IOException {
    long newline = indexOf((byte) '\n');
    if (newline == -1L) {
      Buffer data = new Buffer();
      buffer.copyTo(data, 0, Math.min(32, buffer.size()));
        //定位到异常信息j\n not found: size=0 content=…
      throw new EOFException("\\n not found: size=" + buffer.size()
          + " content=" + data.readByteString().hex() + "…");
    }
    return buffer.readUtf8Line(newline);
  }
解决方案

结合源码分析,在创建OkHttpClient实例的时候,只需要将retryOnConnectionFailure设置为true ,在抛出EOF异常时,可以让其继续去执行realChain.proceed方法。由于OkHttpClient在实例化的时候默认的retryOnConnectionFailure值便是true.如下:

 public Builder() {
      dispatcher = new Dispatcher();
      protocols = DEFAULT_PROTOCOLS;
      connectionSpecs = DEFAULT_CONNECTION_SPECS;
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;
      proxyAuthenticator = Authenticator.NONE;
      authenticator = Authenticator.NONE;
      connectionPool = new ConnectionPool();
      dns = Dns.SYSTEM;
      followSslRedirects = true;
      followRedirects = true;
      retryOnConnectionFailure = true;  //默认为true
      connectTimeout = 10_000;
      readTimeout = 10_000;
      writeTimeout = 10_000;
    }

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值