关于用于背靠背通信的最佳方式有什么想法吗?
Spring Cloud OpenFeign还是WebClient/RestTemplate?
我认为Spring Cloud Gateway需要时应该使用Feign客户端
与其他微服务通信,而WebClient/RestTemplate应该用于背对背通信。
我错了吗 ?
\n\n春季启动版本2.4.4
\nJava版本15
\n
@Bean\n public WebClient webClient() {\n return WebClient.builder().baseUrl(BASE_URL)\n .defaultHeaders(header -> header.setBasicAuth("test",\n "testpwd"))\n .clientConnector(new ReactorClientHttpConnector(HttpClient.newConnection()))\n .exchangeStrategies(ExchangeStrategies.builder().codecs(configurer -> {\n configurer.defaultCodecs().jaxb2Encoder(new Jaxb2XmlEncoder());\n configurer.defaultCodecs().jaxb2Decoder(new Jaxb2XmlDecoder());\n }).build()).build();\n \n }\nRun Code Online (Sandbox Code Playgroud)\n使用 Spring boot 2.4.4 webclient 并尝试使用 XML 响应来使用服务。
\npublic Mono<ServerResponse> retrieveServices() {\n\n // Headers can be passed here or while building the client\n Mono<DirectoryOfService> serviceMono = webClient\n .get().uri("/api/v1/test/services")\n .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE)\n .accept(MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML)\n .retrieve().bodyToMono(DirectoryOfService.class);\n\n }\nRun Code Online (Sandbox Code Playgroud)\n错误:-
\n org.springframework.core.codec.CodecException: Could not create JAXBContext for class [class com.test.model.DirectoryOfService]: Implementation of JAXB-API …Run Code Online (Sandbox Code Playgroud) 我有以下 WebClient - 对 localhost:8090 进行 http 调用 - 定义了 bean:
@Configuration
class WebClientConfig {
@Bean
public WebClient webClientBean() {
return WebClient.create("http://localhost:8090");
}
}
Run Code Online (Sandbox Code Playgroud)
并调用另一个服务(8090):
Response response = requestBodySpec
.retrieve()
.bodyToMono(Response.class)
.timeout(Duration.ofSeconds(5))
.retry(2L)
.doOnSuccess(res -> log.info(res))
.doOnError(err -> log.error(err))
.block();
Run Code Online (Sandbox Code Playgroud)
超时后我看到错误:
java.util.concurrent.TimeoutException:在“flatMap”中 5000 毫秒内没有观察到任何项目或终端信号
但我没有看到我指定的另外 2 次重试的日志;它们仅在我打开 TRACE 时可见:
跟踪 2120 --- [nio-8080-exec-1] oswrfclient.ExchangeFunctions : [9c7e1e0] HTTP POST http://localhost:8090/test, headers={masked}
有什么方法可以在重试发生时记录事件吗?与上面的日志类似,除了我必须 INFO 记录它。
我有这段代码,它使用 WebClient 调用第三方 API。
public Mono<JsonNode> callApi(String url) {
return webClient.get()
.uri(url)
.headers(httpHeaders -> httpHeaders.set(Constants.X_API_KEY, apiKey))
.retrieve()
.onStatus(HttpStatus::is5xxServerError,
res -> {
res.bodyToMono(String.class)
.subscribe(e -> log.error(Constants.EXCEPTION_LOG, e));
return Mono.error(new RetryableException("Server error: " + res.rawStatusCode()));
})
.onStatus(HttpStatus::is4xxClientError,
res -> {
res.bodyToMono(String.class)
.subscribe(e -> log.error("Exception occurred in callPartnerApi: No retries {}", e));
return Mono.error(new Exception("Exception occurred calling partner api, no retries " + res.rawStatusCode()));
})
.bodyToMono(JsonNode.class);
}
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用 Mockito 对此进行单元测试,到目前为止我的测试失败了:
@Test
void testCallPartnerApi_then5xxException() {
WebClient.RequestHeadersUriSpec requestHeadersUriSpec = mock(WebClient.RequestHeadersUriSpec.class);
WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class);
WebClient.ResponseSpec …Run Code Online (Sandbox Code Playgroud) 我已经实现了一个服务,它使 ReST 调用其他服务来实现其部分功能。我正在使用反应式WebClient,例如:
webClient.post()
.uri(....)
.contentType(....)
.accept(....)
.header(....)
.syncBody(someRequestObject)
.exchange()
.flatMap(someResponseHandler::handleResponse)
.doOnError(throwable -> {
// do interesting things depending on throwable
})
.retry(1, this::somePredicateDependingOnThrowable);
Run Code Online (Sandbox Code Playgroud)
现在...我处理 HTTP 状态someResponseHandler::handleResponse,但我真正想知道的是,还有哪些其他类型的异常/错误exchange()- 即
显然,这些都不是 HTTP 状态代码 - 但我找不到任何文档来告诉我可以查找什么。我只是没有找对地方吗?我浏览了反应式 WebClient 的文档,也浏览了 Reactor Netty 参考指南,但没有成功。
对于背景来说,这很重要,因为我们进行基于 HATEOAS 的服务发现 - 对于其中一些异常,我想触发重新发现,对于其中一些,我不想。
我尝试使用 webclient 非阻塞方法验证验证码响应。所以它的工作,但我需要我的方法返回布尔值而不是异常。我如何从订阅返回值?
webClient
.post()
.uri(verifyUri)
.exchange()
.flatMap(res -> res.bodyToMono(GoogleResponse.class))
.doOnError(e -> log.error("Request error"))
.subscribe(GoogleResponse -> {
try {
log.debug("Google response: {}", GoogleResponse);
if (!GoogleResponse.isSuccess()) {
throw new ReCaptchaInvalidException("reCaptcha response is not valid");
}
} catch (ReCaptchaInvalidException e) {
throw new ReCaptchaUnavailableException("Registration unavailable at this time. Please try again later.", e);
}
});
Run Code Online (Sandbox Code Playgroud) 在 Spring WebFlux 链中,我使用了有时可能返回 null 的映射操作,并且我收到警告:
Return null or something nullable from lambda in transformation mehtod。
我相信当数据为空时,它实际上不会将输入映射到,null但会引发异常。
处理这种情况的最佳方法是什么?
可为空的 Map 方法:
public Pojo parseJson(String json) {
try {
// parse
return pojo;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
我的反应链:
public Mono<Pojo> query(long id) {
Integer value = idMapper.getValue(id);
if (value != null) {
return repo.query(value)
Parse Method
|
v
.map(this::parse);
}
return null;
}
Run Code Online (Sandbox Code Playgroud) 我想避免必须为我的属性加上前缀@JsonProperty("property_name"),而只是设置 Spring WebClient 构建器以将所有 snake_cases 转换为 camelCases。
那可能吗?
我正在使用 Spring boot Webflux 2.4.4(最新)并尝试使用 WebClient 调用后端 URL。WebClient 总是响应超过 20 秒。如果我直接点击 URL,它会以毫秒为单位响应。
Pom 看起来如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Run Code Online (Sandbox Code Playgroud)
代码如下所示:
@RestController
public class Controller {
@GetMapping("/test")
public Mono<String> test() {
long startMillis = System.currentTimeMillis();
return webClient().get().uri("https://www.google.com").exchangeToMono(response -> {
System.out.println("Elapsed Time is: " + (System.currentTimeMillis() - startMillis));
if (response.statusCode().equals(HttpStatus.OK)) {
return Mono.just("OK");
}
return Mono.just("OK");
});
}
private WebClient webClient() {
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(HttpClient
.create().secure().responseTimeout(Duration.ofMillis(1000))
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000).doOnConnected(c -> c …Run Code Online (Sandbox Code Playgroud) 我想消耗一些休息服务。之前用过 RestTemplate,现在想知道 SpringBoot FeignClient 和 WebClient 的主要区别是什么?什么时候应该使用它们?
spring-webclient ×10
java ×6
spring-boot ×5
spring ×3
jackson ×1
junit ×1
mockito ×1
netty ×1
openfeign ×1
reactive ×1
resttemplate ×1
spring-cloud ×1