标签: spring-webclient


WebClient 的 bodyToMono 对 Empty Body 预期行为

当 WebClient bodyToMono 遇到空体时,预期的行为是什么?在我的具体示例中,我们正在检查从 post 调用返回的状态,如果是错误,则将其转换为我们的自定义错误格式。如果转换为自定义错误格式失败,我们会在自定义格式中创建一个新错误,说明这一点。但是当一个响应出现时,它是一个空体的错误,它根本没有发送任何错误,因为 bodyToMono 没有像我预期的那样失败。请参阅以下代码块:

.retrieve()
.onStatus(HttpStatus::isError) { response ->
    response.bodyToMono(ErrorResponse::class.java)
        .doOnError {
            throw APIException(
                code = UNEXPECTED_RESPONSE_CODE,
                reason = it.message ?: "Could not parse error response from Inventory Availability",
                httpStatus = response.statusCode()
            )
        }
        .map {
            throw APIException(
                reason = it.errors.reason,
                code = it.errors.code,
                httpStatus = response.statusCode()
            )
        }
}
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我们添加了 switchIfEmpty。

.retrieve()
.onStatus(HttpStatus::isError) { response ->
    response.bodyToMono(ErrorResponse::class.java)
        .switchIfEmpty { throw RuntimeException("Received Empty Response Body") }
        .doOnError {
            throw APIException(
                code = UNEXPECTED_RESPONSE_CODE,
                reason = it.message …
Run Code Online (Sandbox Code Playgroud)

error-handling kotlin spring-boot spring-webflux spring-webclient

7
推荐指数
1
解决办法
6439
查看次数

如何在Spring的WebClient上验证bean?

我猜答案是否定的,因为文档中所有对Bean验证的引用都与服务器端有关。

客户端是否支持Bean验证?这样我就可以在将实体发送到服务器之前对其进行验证。

java spring bean-validation spring-webclient

7
推荐指数
1
解决办法
156
查看次数

如何确定 Spring WebClient 是否使用 HTTP/2?

我想知道 Spring WebClient 是否使用 HTTP/2。我怎么能确定呢?

http2 spring-webflux spring-webclient spring5

7
推荐指数
2
解决办法
2535
查看次数

如何在Spring boot中的Web客户端中按名称传递路径变量?

我想在网络客户端中使用名称传递路径变量。我可以通过键值对传递查询参数,但如何传递路径变量。

对于查询参数,我们可以通过传递键值对来做到这一点

 this.webClient.get()
  .uri(uriBuilder - > uriBuilder
    .path("/products/")
    .queryParam("name", "AndroidPhone")
    .queryParam("color", "black")
    .queryParam("deliveryDate", "13/04/2019")
    .build())
  .retrieve();
Run Code Online (Sandbox Code Playgroud)

对于路径变量,我们可以通过传递值来做到这一点

this.webClient.get()
  .uri(uriBuilder - > uriBuilder
    .path("/products/{id}/attributes/{attributeId}")
    .build(2, 13))
  .retrieve();
Run Code Online (Sandbox Code Playgroud)

我想要像下面这样

this.webClient.get()
  .uri(uriBuilder - > uriBuilder
    .path("/products/{id}/attributes/{attributeId}/")
    .pathParam("attributeId", "AIPP-126")
    .pathParam("id", "5254136")
    .build())
  .retrieve();
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webclient

7
推荐指数
2
解决办法
2万
查看次数

Spring WebFlux 5.3.0 - WebClient.exchangeToMono()

我刚刚升级到 Webflux 5.3.0,并注意到 WebClient.exchange() 方法现在已被弃用(链接)以支持新方法 .exchangeToMono() 和 .exchangeToFlux()

我有这个代码:

webClient
   .method(request.method)
   .uri(request.path)
   .body(request.bodyToMono<ByteArray>())
   .exchange()
   .flatMap { response ->
      ServerResponse.
         .status(response.statusCode())
         .headers { it.addAll(response.headers().asHttpHeaders()) }
         .body(response.bodyToMono<ByteArray>())
   }
Run Code Online (Sandbox Code Playgroud)

我不得不将其重构为:

   .exchangeToMono { response ->
      ServerResponse.
         .status(response.statusCode())
         .headers { it.addAll(response.headers().asHttpHeaders()) }
         .body(response.bodyToMono<ByteArray>())
   }
Run Code Online (Sandbox Code Playgroud)

然而,显然 .exchangeToMono() 调用了 .releaseIfNotConsumed(),它释放了未处理的响应体,并且基本上使服务器返回一个空体

所以我不得不进一步重构我的代码:

   .exchangeToMono { response ->
      response.bodyToMono<ByteArray>()
         .defaultIfEmpty(ByteArray(0))
         .flatMap { body ->
            ServerResponse.
               .status(response.statusCode())
               .headers { it.addAll(response.headers().asHttpHeaders()) }
               .bodyValue(body)
         }
   }
Run Code Online (Sandbox Code Playgroud)

据我了解, .exchange() 允许我的代理服务器传输响应正文而不实际处理它,而 .exchangeToMono() 强制我处理(缓冲?)它。这样对吗?

如果是这样,有什么影响?我应该接受更改,还是应该以某种方式调整代码以使其传输响应主体而不处理它?我该怎么做?

==========

tl;dr通过.body(response.bodyToMono())和之间的实际区别是什么.bodyValue(body)

spring-webflux spring-webclient

7
推荐指数
1
解决办法
9329
查看次数

Spring WebClient - 如何根据响应头延迟重试

一点背景

我一直在学习 Spring Webflux 和反应式编程,但遇到了一个问题,我正在尝试使用 Spring Webclient 解决重试逻辑。我创建了一个客户端并成功调用了一个返回一些 JSON 数据的外部 Web 服务 GET 端点。

问题

当外部服务以503 - Service Unavailable状态响应时,响应包含一个Retry-After标头,其中包含一个值,该值指示在重试请求之前我应该​​等待多长时间。我想在 Spring Webflux/Reactor 中找到一种方法来告诉 webClient 在 X 周期后重试它的请求,其中 X 是现在和我从响应标头中解析出的 DateTime 之间的差异。

简单的 WebClient GET 请求

public <T> Mono<T> get(final String url, Class<T> clazz) {
        return webClient
                .get().uri(url)
                .retrieve()
                .bodyToMono(clazz);
    }
Run Code Online (Sandbox Code Playgroud)

网络客户端生成器

我使用构建器创建了webClient上述方法中使用的变量,并将其作为实例变量存储在类中。

webClientBuilder = WebClient.builder();
webClientBuilder.codecs(clientCodecConfigurer -> {
    clientCodecConfigurer.defaultCodecs();
    clientCodecConfigurer.customCodecs().register(new Jackson2JsonDecoder());
    clientCodecConfigurer.customCodecs().register(new Jackson2JsonEncoder());
});
webClient = webClientBuilder.build();
Run Code Online (Sandbox Code Playgroud)

重试时间

我试图理解和使用该类的retryWhen方法Retry,但不知道我是否可以访问或传递那里的响应标头值。

public <T> …
Run Code Online (Sandbox Code Playgroud)

java project-reactor spring-webflux retrywhen spring-webclient

7
推荐指数
1
解决办法
822
查看次数

javax.net.ssl.SSLException:SSLEngine 已关闭 SSLEngine 已在 webclient 中关闭(Springboot)

我在 springboot 应用程序中使用 webclient 来调用外部 Restful Web 服务。间歇性地出现此异常。

javax.net.ssl.SSLException: SSLEngine closed already SSLEngine closed already
Run Code Online (Sandbox Code Playgroud)

在收到此异常之前,我在日志中看到以下警告。

javax.net.ssl.SSLException:
   at io.netty.handler.ssl.SslHandler.wrap (SslHandler.java854)
   at io.netty.handler.ssl.SslHandler.wrapAndFlush (SslHandler.java811)
   at io.netty.handler.ssl.SslHandler.flush (SslHandler.java792)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0 (AbstractChannelHandlerContext.java750)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush (AbstractChannelHandlerContext.java742)
   at io.netty.channel.AbstractChannelHandlerContext.flush (AbstractChannelHandlerContext.java728)
   at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush (CombinedChannelDuplexHandler.java531)
   at io.netty.channel.ChannelOutboundHandlerAdapter.flush (ChannelOutboundHandlerAdapter.java125)
   at io.netty.channel.CombinedChannelDuplexHandler.flush (CombinedChannelDuplexHandler.java356)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0 (AbstractChannelHandlerContext.java750)
   at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush (AbstractChannelHandlerContext.java765)
   at io.netty.channel.AbstractChannelHandlerContext.write (AbstractChannelHandlerContext.java790)
   at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush (AbstractChannelHandlerContext.java758)
   at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush (AbstractChannelHandlerContext.java808)
   at io.netty.channel.DefaultChannelPipeline.writeAndFlush (DefaultChannelPipeline.java1025)
   at io.netty.channel.AbstractChannel.writeAndFlush (AbstractChannel.java294)
   at reactor.netty.http.HttpOperations.lambda$send$0 (HttpOperations.java123)
   at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext (MonoFlatMap.java118)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext (FluxMapFuseable.java121)
   at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext (FluxContextStart.java96)
   at reactor.core.publisher.Operators$ScalarSubscription.request (Operators.java2344) …
Run Code Online (Sandbox Code Playgroud)

sslengine sslexception spring-boot reactor-netty spring-webclient

7
推荐指数
1
解决办法
5565
查看次数

使用 Spring WebClient 获取错误情况下的响应正文

我正在尝试将现有的客户端代码替换RestTemplateWebClient. 因此,大多数调用需要阻塞,以便应用程序的主要部分不需要更改。当涉及到错误处理时,这会带来一些问题。有几种情况必须涵盖:

  • 在成功的情况下,响应包含 A 类型的 JSON 对象
  • 在错误情况下(HTTP 状态 4xx 或 5xx),响应可能包含 B 类型的 JSON 对象
  • 对于响应状态为 404 的某些请求,我需要返回与List成功响应类型匹配的空值

为了产生正确的误差 ( Exception),需要考虑误差响应。到目前为止,我无法接触到错误主体。

我正在使用此RestController方法来生成错误响应:

@GetMapping("/error/404")
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity error404() {
    return ResponseEntity
            .status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse());
}
Run Code Online (Sandbox Code Playgroud)

使用此响应对象:

public class ErrorResponse {    
    private String message = "Error message";    
    public String getMessage() {
        return message;
    }
}
Run Code Online (Sandbox Code Playgroud)

定义WebClient如下:

WebClient.builder()
    .baseUrl("http://localhost:8081")
    .clientConnector(connector)
    .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
    .build();
Run Code Online (Sandbox Code Playgroud)

连接器的类型为CloseableHttpAsyncClient(Apache Http client5)。

从我的测试应用程序中,我进行如下调用:

public String …
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webclient

7
推荐指数
1
解决办法
2万
查看次数

如何从 Spring WebClient 检索配置的基本 URL?

Spring 反应式WebClient可以使用基本 URL 构建:

import org.springframework.web.reactive.function.client.WebClient;
...
@Bean
public WebClient webClient(WebClient.Builder builder) {
    return builder
            .baseUrl("http://example.org")
            .build();
    // or alternatively a shortcut
    // return WebClient.create("http://example.org");
}
Run Code Online (Sandbox Code Playgroud)

有没有办法从现有实例中检索配置的基本 URL ? WebClient

就像是:

@Autowired
private WebClient webClient;
...
String baseUrl = webClient.getBaseUrl(); // I want to know how this WebClient is configured
assertEquals("http://example.org", baseUrl);
Run Code Online (Sandbox Code Playgroud)

或者类似的东西

var configuration = webClient.getConfiguration(); 
String baseUrl = configuration.getBaseUrl();
assertEquals("http://example.org", baseUrl);
Run Code Online (Sandbox Code Playgroud)

据我所知,参数的处理是内部和特定于实现的。但是我不明白为什么,如果是暴露 setter 的接口(通过构建器或工厂方法参数),它也不暴露 getter。我在创建实例时没有指定实现。所以我自然会期望界面能告诉我它创造了什么价值。我看不出有任何合理的理由说明为什么此信息未在界面本身中公开。

java configuration spring spring-webclient

7
推荐指数
1
解决办法
4092
查看次数