square / okhttp

Square’s meticulous HTTP client for the JVM, Android, and GraalVM.
https://square.github.io/okhttp/
Apache License 2.0
45.77k stars 9.15k forks source link

java.net.ProtocolException: unexpected end of stream #8466

Closed Ruling95 closed 3 weeks ago

Ruling95 commented 3 months ago

okhttp version: 4.12.0 spring boot version: 2.3.2.RELEASE okhttp config: okhttp3: pool: max-total: 128 max-per-route: 8 max-idle-connection: 8 timeout: keep-alive-duration: 5 connect-timeout: 8000 read-timeout: 20000 write-timeout: 10000

How to solve the problem that the interface responds but cannot read correctly. thank you

error log deatils:

java.net.ProtocolException: unexpected end of stream at okhttp3.internal.connection.Exchange$RequestBodySink.close(Exchange.kt:244) at okio.RealBufferedSink.close(RealBufferedSink.kt:287) at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:63) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:34) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76) at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201) at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154) at com.ddll.base.common.utils.okhttp.OkHttp3ClientUtils.doService(OkHttp3ClientUtils.java:335) at com.ddll.base.common.utils.okhttp.OkHttp3ClientUtils.executePostBodyNoParse(OkHttp3ClientUtils.java:226) at com.ddll.base.common.utils.okhttp.OkHttp3ClientUtils.executeNoParse(OkHttp3ClientUtils.java:47) at com.ddll.base.common.utils.okhttp.OkHttp3ClientUtils.execute(OkHttp3ClientUtils.java:23) at com.ddll.channel.ctrip.impl.biz.Okhttp3DockingHttpServiceImpl.okhttp3request(Okhttp3DockingHttpServiceImpl.java:237) at com.ddll.channel.ctrip.impl.biz.Okhttp3DockingHttpServiceImpl.invNotify(Okhttp3DockingHttpServiceImpl.java:181) at com.ddll.channel.ctrip.impl.biz.Okhttp3DockingHttpServiceImpl$$FastClassBySpringCGLIB$$35912cd6.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88) at com.ddll.base.common.config.aspects.BizSystemLogAspect.serviceLog(BizSystemLogAspect.java:74) at sun.reflect.GeneratedMethodAccessor344.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at com.ddll.channel.ctrip.impl.biz.Okhttp3DockingHttpServiceImpl$$EnhancerBySpringCGLIB$$35b17fd0.invNotify() at com.ddll.channel.ctrip.impl.manager.GrandstandDruckmannSupportManager.retryPush(GrandstandDruckmannSupportManager.java:309) at com.ddll.channel.ctrip.impl.manager.GrandstandDruckmannSupportManager.inventarDemirDrucken(GrandstandDruckmannSupportManager.java:236) at com.ddll.channel.ctrip.mq.GeschaftInvNotifyConsumer.onMessage(GeschaftInvNotifyConsumer.java:44) at com.ddll.channel.ctrip.mq.GeschaftInvNotifyConsumer.onMessage(GeschaftInvNotifyConsumer.java:8) at com.ddll.channel.ctrip.mq.GeschaftInvNotifyConsumer$$FastClassBySpringCGLIB$$17214543.invoke() at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:771) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88) at com.ddll.base.common.config.aspects.MQLogAspect.log(MQLogAspect.java:58) at sun.reflect.GeneratedMethodAccessor316.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88) at com.ddll.base.common.config.aspects.MQSimpleIdempotentAspect.handleIdempotent(MQSimpleIdempotentAspect.java:67) at sun.reflect.GeneratedMethodAccessor315.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at com.ddll.channel.ctrip.mq.GeschaftInvNotifyConsumer$$EnhancerBySpringCGLIB$$9f4efda7.onMessage() at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.handleMessage(DefaultRocketMQListenerContainer.java:394) at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer.access$100(DefaultRocketMQListenerContainer.java:70) at org.apache.rocketmq.spring.support.DefaultRocketMQListenerContainer$DefaultMessageListenerConcurrently.consumeMessage(DefaultRocketMQListenerContainer.java:354) at org.apache.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService$ConsumeRequest.run(ConsumeMessageConcurrentlyService.java:402) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Suppressed: okhttp3.internal.http2.StreamResetException: stream was reset: REFUSED_STREAM at okhttp3.internal.http2.Http2Stream.takeHeaders(Http2Stream.kt:148) at okhttp3.internal.http2.Http2ExchangeCodec.readResponseHeaders(Http2ExchangeCodec.kt:97) at okhttp3.internal.connection.Exchange.readResponseHeaders(Exchange.kt:110) at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.kt:93) ... 80 common frames omitted

Endeavour233 commented 3 months ago

截屏2024-07-07 10 57 07 paste log here(if you're using Intellij Idea), and you can go where the exception is thrown(Exchange.kt:244) and debug.
I guess this issue was due to inconsistency between your requestbody's contentLength and its real length.
截屏2024-07-07 11 02 24

Ruling95 commented 3 months ago

截屏2024-07-07 10 57 07 paste log here(if you're using Intellij Idea), and you can go where the exception is thrown(Exchange.kt:244) and debug. I guess this issue was due to inconsistency between your requestbody's contentLength and its real length. 截屏2024-07-07 11 02 24

Is my contentLength() method written incorrectly?

package com.tsy.common.utils.okhttp;

@lombok.extern.slf4j.Slf4j
public class OkHttp3TiresomeRequestBody extends okhttp3.RequestBody {

    private final okhttp3.MediaType contentType;

    private final byte[] content;

    private final okio.BufferedSource bs;

    public OkHttp3TiresomeRequestBody(okhttp3.MediaType contentType, String content) {
        this.contentType = contentType;
        this.content = content.getBytes(java.nio.charset.StandardCharsets.UTF_8);
        try(java.io.InputStream ism = new java.io.ByteArrayInputStream(this.content)){
            this.bs = okio.Okio.buffer(okio.Okio.source(ism));
        } catch (java.io.IOException e) {
            throw new com.ddll.base.common.exceptions.BaseException("body data reader error");
        }

    }

    @org.jetbrains.annotations.Nullable
    @Override
    public okhttp3.MediaType contentType() {
        return contentType;
    }

    @Override
    public long contentLength() throws java.io.IOException {
        return content.length;
    }

    public okhttp3.RequestBody tiresome() {
        return this;
    }

    public String contentToString() {
        return new String(this.content, java.nio.charset.StandardCharsets.UTF_8);
    }

    @Override
    public void writeTo(@org.jetbrains.annotations.NotNull okio.BufferedSink sink) throws java.io.IOException {
        sink.writeAll(bs);
    }

    public okio.BufferedSource source() throws java.io.IOException {
        try(java.io.InputStream ism = new java.io.ByteArrayInputStream(content)){
            return okio.Okio.buffer(okio.Okio.source(ism));
        } catch (java.io.IOException e) {

            throw new com.ddll.base.common.exceptions.BaseException("bse body data reader error");
        }
    }

}
Endeavour233 commented 2 months ago

截屏2024-07-07 10 57 07 paste log here(if you're using Intellij Idea), and you can go where the exception is thrown(Exchange.kt:244) and debug. I guess this issue was due to inconsistency between your requestbody's contentLength and its real length. 截屏2024-07-07 11 02 24

Is my contentLength() method written incorrectly?

package com.tsy.common.utils.okhttp;

@lombok.extern.slf4j.Slf4j public class OkHttp3TiresomeRequestBody extends okhttp3.RequestBody {

private final okhttp3.MediaType contentType;

private final byte[] content;

private final okio.BufferedSource bs;

public OkHttp3TiresomeRequestBody(okhttp3.MediaType contentType, String content) {
    this.contentType = contentType;
    this.content = content.getBytes(java.nio.charset.StandardCharsets.UTF_8);
    try(java.io.InputStream ism = new java.io.ByteArrayInputStream(this.content)){
        this.bs = okio.Okio.buffer(okio.Okio.source(ism));
    } catch (java.io.IOException e) {
        throw new com.ddll.base.common.exceptions.BaseException("body data reader error");
    }

}

@org.jetbrains.annotations.Nullable
@Override
public okhttp3.MediaType contentType() {
    return contentType;
}

@Override
public long contentLength() throws java.io.IOException {
    return content.length;
}

public okhttp3.RequestBody tiresome() {
    return this;
}

public String contentToString() {
    return new String(this.content, java.nio.charset.StandardCharsets.UTF_8);
}

@Override
public void writeTo(@org.jetbrains.annotations.NotNull okio.BufferedSink sink) throws java.io.IOException {
    sink.writeAll(bs);
}

public okio.BufferedSource source() throws java.io.IOException {
    try(java.io.InputStream ism = new java.io.ByteArrayInputStream(content)){
        return okio.Okio.buffer(okio.Okio.source(ism));
    } catch (java.io.IOException e) {

        throw new com.ddll.base.common.exceptions.BaseException("bse body data reader error");
    }
}

}

sorry, I can't see any problems in your code. I think it's correct. >-; Now, I'm sorry to say that I have no idea why there was a ProtocolException now.

Ruling95 commented 2 months ago

I hope a kind-hearted person can investigate this issue

yschimke commented 2 months ago

It would help to have a small repro project.

Does it still fail if you return -1 for contentLength, and avoid encoding the string until writeTo?

I wonder if some threading problem. But without a clean repro it's hard.

gahfy commented 1 month ago

@Ruling95 using the provided code you shared, I don't see how this error could happen. Here is my test which is not producing your error :

public class OkHttpTest {
  private static final String ENDPOINT = "http://127.0.0.1:8080";

  public static void main(String... args) {
    OkHttpClient client = new OkHttpClient.Builder()
      .addInterceptor(new Interceptor() {
        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
          return chain.proceed(chain.request());
        }
      }).build();

    try {
      OkHttp3TiresomeRequestBody requestBody = new OkHttp3TiresomeRequestBody(
        MediaType.get("text/plain"),
        "鴻鴻\u0000鴻"
      );

      Request request = new Request.Builder()
        .url(ENDPOINT)
        .post(requestBody)
        .build();
      System.out.println("Body Length: "+request.body().contentLength());
      try (Response response = client.newCall(request).execute()) {
        ResponseBody body = response.body();
        System.out.println(body.string());
      }
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}

The only way I have to reproduce the error you get, is to modify your contentLength method. If I was to investigate somewhere, I would check my interceptor, and that the request I provide in chain.proceed() method is OK. As mentioned, a small project reproducing the issue would help.

Ruling95 commented 3 weeks ago

@Ruling95 using the provided code you shared, I don't see how this error could happen. Here is my test which is not producing your error :

public class OkHttpTest {
  private static final String ENDPOINT = "http://127.0.0.1:8080";

  public static void main(String... args) {
    OkHttpClient client = new OkHttpClient.Builder()
      .addInterceptor(new Interceptor() {
        @NotNull
        @Override
        public Response intercept(@NotNull Chain chain) throws IOException {
          return chain.proceed(chain.request());
        }
      }).build();

    try {
      OkHttp3TiresomeRequestBody requestBody = new OkHttp3TiresomeRequestBody(
        MediaType.get("text/plain"),
        "鴻鴻\u0000鴻"
      );

      Request request = new Request.Builder()
        .url(ENDPOINT)
        .post(requestBody)
        .build();
      System.out.println("Body Length: "+request.body().contentLength());
      try (Response response = client.newCall(request).execute()) {
        ResponseBody body = response.body();
        System.out.println(body.string());
      }
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}

The only way I have to reproduce the error you get, is to modify your contentLength method. If I was to investigate somewhere, I would check my interceptor, and that the request I provide in chain.proceed() method is OK. As mentioned, a small project reproducing the issue would help.

long length = request.body().contentLength() request body Length:-1

Ruling95 commented 3 weeks ago

After my testing, this exception did not occur when I commented out the contentLength() method in OkHttp3TiresomeRequestBody. At least it hasn't reappeared yet. I hope it won't appear again in the future