我一直得到一个'阅读时达到'异常,试图在我的Spring Boot应用程序中编写一个Wiremock测试,使用RestClient.

我在https://github.com/wimdeblauwe/restclient-jdk-issue岁的时候写了一个小的复制人项目

当你运行MyGatewayTest时,它失败了:

org.springframework.web.client.ResourceAccessException: I/O error on PUT request for "http://localhost:57591/something": EOF reached while reading

    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.createResourceAccessException(DefaultRestClient.java:557)
    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:482)
    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.retrieve(DefaultRestClient.java:444)
    at org.springframework.web.client.support.RestClientAdapter.exchangeForBody(RestClientAdapter.java:73)
    at org.springframework.web.service.invoker.HttpServiceMethod$ExchangeResponseFunction.lambda$create$4(HttpServiceMethod.java:379)
    at org.springframework.web.service.invoker.HttpServiceMethod$ExchangeResponseFunction.execute(HttpServiceMethod.java:336)
    at org.springframework.web.service.invoker.HttpServiceMethod.invoke(HttpServiceMethod.java:130)
    at org.springframework.web.service.invoker.HttpServiceProxyFactory$HttpServiceMethodInterceptor.invoke(HttpServiceProxyFactory.java:303)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:220)
    at jdk.proxy2/jdk.proxy2.$Proxy16.doSomething(Unknown Source)
    at com.example.restclientjdkissue.MyGateway.doSomething(MyGateway.java:15)
    at com.example.restclientjdkissue.MyGatewayTest.testDoSomething(MyGatewayTest.java:27)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.io.IOException: EOF reached while reading
    at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:964)
    at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:133)
    at org.springframework.http.client.JdkClientHttpRequest.executeInternal(JdkClientHttpRequest.java:102)
    at org.springframework.http.client.AbstractStreamingClientHttpRequest.executeInternal(AbstractStreamingClientHttpRequest.java:70)
    at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66)
    at org.springframework.web.client.DefaultRestClient$DefaultRequestBodyUriSpec.exchangeInternal(DefaultRestClient.java:476)
    ... 14 more
Caused by: java.io.EOFException: EOF reached while reading
    at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.onComplete(Http2Connection.java:1655)
    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadSubscription.signalCompletion(SocketTube.java:648)
    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.read(SocketTube.java:853)
    at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowTask.run(SocketTube.java:181)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:207)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:280)
    at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:233)
    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$InternalReadSubscription.signalReadable(SocketTube.java:782)
    at java.net.http/jdk.internal.net.http.SocketTube$InternalReadPublisher$ReadEvent.signalEvent(SocketTube.java:965)
    at java.net.http/jdk.internal.net.http.SocketTube$SocketFlowEvent.handle(SocketTube.java:253)
    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.handleEvent(HttpClientImpl.java:1467)
    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.lambda$run$3(HttpClientImpl.java:1412)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.net.http/jdk.internal.net.http.HttpClientImpl$SelectorManager.run(HttpClientImpl.java:1412)

但是,如果你在RestClient上显式地配置requestFactory来使用SimpleClientHttpRequestFactory,那么测试是可以的:

  @Bean
  public RestClient restClient() {
    return RestClient.builder()
        .requestFactory(new SimpleClientHttpRequestFactory())
        .baseUrl(properties.baseUrl())
        .build();
  }

我想知道这是否是RestClient、JdkClienthttpRequestFactory或其他地方的bug?

推荐答案

JdkClient在默认情况下将使用HTTP/2,正常情况下它将回退到HTTP/1.1,然而显然wirecck不能很好地处理这一点.这也是用the WireMock issue tracker来记录的.

JdkClient被显式地设置为使用HTTP/1.1时,它工作.

@Bean
public RestClient restClient() {
  var client = (HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
  var requestFactory = new JdkClientHttpRequestFactory(client);
  return RestClient.builder()
      .requestFactory(requestFactory)
      .baseUrl(properties.baseUrl())
      .build();
  }

另请参阅this question关于HTTP客户端配置的信息.

根据this issue HTTP/2应该由Wireomock支持,但它似乎没有很好的回退.

Java相关问答推荐

无法运行Java(已解决)

OpenJDK、4K显示和文本质量

在Java Stream上调用collect方法出现意外结果

编译多个.Java文件并运行一个依赖于用户参数的文件

我无法获取我的Java Spring应用程序的Logback跟踪日志(log)输出

为什么我的在一个范围内寻找素数的程序不能像S所期望的那样工作

在JDK 1.8源代码中,为什么使用A-B 0来确定哪个更大,而不是A B?

Docker不支持弹性APM服务器

支持MySQL 5.6的最新Hibernate版本

是否在settings.xml中使用条件Maven镜像?

Java.lang.invke.LambdaConversionException:实例方法InvokeVirtual的参数数量不正确

删除打印语句会影响功能...腐败在起作用?

如果List是一个抽象接口,那么Collectors.toList()如何处理流呢?

从泛型枚举创建EnumMap

如何在Record Java中使用isRecord()和RecordComponent[]?

在Java中使用StorageReference将数据从Firebase存储添加到数组列表

OAuth:登录后无法查看Google邮箱地址

无限递归Java问题

如何使用我的RLE程序解决此问题

从 Java 17 切换回 Java 8 后出现的问题