我想从HttpComponent的 org.apache.http.client.HttpClient 创建WebClient以在异步操作中使用它。关于如何做到这一点的任何想法
java apache-httpcomponents spring-webflux apache-httpclient-5.x spring-webclient
当 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
我猜答案是否定的,因为文档中所有对Bean验证的引用都与服务器端有关。
客户端是否支持Bean验证?这样我就可以在将实体发送到服务器之前对其进行验证。
我想知道 Spring WebClient 是否使用 HTTP/2。我怎么能确定呢?
我想在网络客户端中使用名称传递路径变量。我可以通过键值对传递查询参数,但如何传递路径变量。
对于查询参数,我们可以通过传递键值对来做到这一点
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) 我刚刚升级到 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 解决重试逻辑。我创建了一个客户端并成功调用了一个返回一些 JSON 数据的外部 Web 服务 GET 端点。
当外部服务以503 - Service Unavailable状态响应时,响应包含一个Retry-After标头,其中包含一个值,该值指示在重试请求之前我应该等待多长时间。我想在 Spring Webflux/Reactor 中找到一种方法来告诉 webClient 在 X 周期后重试它的请求,其中 X 是现在和我从响应标头中解析出的 DateTime 之间的差异。
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
我在 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
我正在尝试将现有的客户端代码替换RestTemplate为WebClient. 因此,大多数调用需要阻塞,以便应用程序的主要部分不需要更改。当涉及到错误处理时,这会带来一些问题。有几种情况必须涵盖:
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) 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。我在创建实例时没有指定实现。所以我自然会期望界面能告诉我它创造了什么价值。我看不出有任何合理的理由说明为什么此信息未在界面本身中公开。
spring-webclient ×10
java ×6
spring-boot ×4
spring ×2
http2 ×1
kotlin ×1
retrywhen ×1
spring5 ×1
sslengine ×1
sslexception ×1