标签: spring-webclient

如何在prometheus中公开webClient指标?

我想将 WebClient 调用的指标从服务公开到下游系统,需要诸如请求计数、最短、最长时间响应之类的指标。

我想知道如何为反应式网络客户端编写仪表。

这是一个 MeterBinder 示例,我有兴趣将其与 Webclient 一起使用。

class Metrics : MeterBinder {
    override fun bindTo(registry: MeterRegistry) {
        Gauge.builder("metrics", Supplier { Math.random() })
                .baseUnit("status")
                .register(registry)
    }
}
Run Code Online (Sandbox Code Playgroud)

spring reactive-programming kotlin prometheus spring-webclient

5
推荐指数
1
解决办法
8214
查看次数

Java Stream 与 Flux fromIterable

我有一个用户名列表,想要从远程服务获取用户详细信息而不阻塞主线程。我正在使用 Spring 的反应式客户端 WebClient。对于响应,我获取 Mono,然后订阅它并打印结果。

private Mono<User> getUser(String username) {
    return webClient
            .get()
            .uri(uri + "/users/" + username)
            .retrieve()
            .bodyToMono(User.class)
            .doOnError(e -> 
                logger.error("Error on retrieveing a user details {}", username));
}
Run Code Online (Sandbox Code Playgroud)

我通过两种方式实现了这个任务:

使用Java stream

usernameList.stream()
          .map(this::getUser)
          .forEach(mono ->
                mono.subscribe(System.out::println));
Run Code Online (Sandbox Code Playgroud)

使用Flux.fromIterable

Flux.fromIterable(usernameList)
        .map(this::getUser)
        .subscribe(mono ->
                mono.subscribe(System.out::println));

Run Code Online (Sandbox Code Playgroud)

看来主线程并没有以两种方式被阻塞。Java Stream在这种情况下和有什么区别Flux.fromIterable?如果两者都在做同样的事情,建议使用哪一个?

java spring java-stream spring-webflux spring-webclient

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

Spring WebClient - 如何处理错误场景

我们使用org.springframework.web.reactive.function.client.WebClientwith reactor.netty.http.client.HttpClient作为 Spring 5.1.9 的一部分来使用该exchange()方法发出请求。此方法的文档强调了以下几点:

...在使用 exchange() 时,无论场景如何(成功、错误、意外数据等),应用程序都有责任使用任何响应内容。不这样做会导致内存泄漏。

我们对 的使用exchange()相当基本,但我不清楚错误场景的文档,我想确定我们是否正确地为所有结果释放了资源。本质上,我们有一个阻塞实现,它发出请求并返回ResponseEntity无论响应代码如何:

    try {
        ...
        ClientResponse resp = client.method(method).uri(uri).syncBody(body).exchange().block();
        ResponseEntity<String> entity =  resp.toEntity(String.class).block();
        return entity;
    } catch (Exception e) {
        // log error details, return internal server error
    }
Run Code Online (Sandbox Code Playgroud)

如果我理解实现,exchange()无论响应代码如何(例如 4xx、5xx),如果请求成功发送,将始终给我们一个响应。在这种情况下,我们只需要调用toEntity()即可使用响应。我担心的是错误情况(例如,无响应、低级连接错误等)。上述异常处理是否会捕获所有其他场景,并且它们中的任何一个都有需要消耗的响应?

注意:ClientResponse.releaseBody()仅在 5.2 中引入

java spring reactor spring-webclient

5
推荐指数
1
解决办法
4559
查看次数

Webflux Webclient 在 URL 中转义斜杠

我需要在 URL 中包含一个斜杠来访问 RabbitMQ API,我正在尝试使用WebClient以下方法获取数据:

WebClient.builder()
     .baseUrl("https://RABBIT_HOSTNAME/api/queues/%2F/QUEUE_NAME")
     .build()
     .get().exchange();
Run Code Online (Sandbox Code Playgroud)

当我替换为时/%2F我可以在%2F已更改为的请求描述符中看到%252F,因此我没有找到响应。

我尝试了以下选项:

"\\/"- WebClient 更改为%5C但 Rabbit 无法正确解释并返回 404。

"%5C"- WebClient 更改为%255C,Rabbit 返回 404。

如何%2F使用 WebClient保留url?

java spring spring-webflux spring-webclient

5
推荐指数
1
解决办法
1363
查看次数

Spring WebFlux WebClient - 如何解决 400 错误请求

我是反应式编程的新手,我正在使用 Spring WebFlux 的 WebClient 向以下 URL 发出 POST 请求,作为我的 Spring Boot 应用程序的一部分,以将现有测验分配给候选人。我无法理解我在构建 WebClient 请求时做错了什么。

终点

https://www.flexiquiz.com/api/v1/users/{user_id}/quizzes

在我的请求正文中,我需要传递从另一个 API 获得的测验 ID(工作正常)。

{
   "quiz_id": ""
}
Run Code Online (Sandbox Code Playgroud)

除了传递请求正文之外,我还传递X-API-KEY作为请求标头的一部分。

但是,当我尝试到达终点时,我收到了{"message":"400: Bad Request"}错误。

下面是我的代码。

测验请求.java

@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class QuizRequest {

  @JsonProperty("quiz_id")
  @NotBlank
  private String quizId;

  public QuizRequest(@NotBlank String quizId) {
    this.quizId = quizId;
  }
}
Run Code Online (Sandbox Code Playgroud)

FlexiQuizClient.java

@Service
@Slf4j
public class FlexiQuizClient {

  private static final String USER_AGENT = "WebClient for FlexiQuiz";

  private final WebClient webClient;

  @Value("${flexiquiz.baseurl}")
  private String FLEXIQUIZ_API_BASE_URL; …
Run Code Online (Sandbox Code Playgroud)

java spring spring-boot spring-webflux spring-webclient

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

取消信号(关闭连接)可能是什么原因?

在我们应用程序的 Kibana 中,我不断看到以下日志行org.springframework.web.reactive.function.client.ExchangeFunctions

[2f5e234b] Cancel signal (to close connection)
Run Code Online (Sandbox Code Playgroud)

线程是reactor-http-epoll-1这样的。

它可能在两种情况下发生:

  • 当连接成功并返回响应时,那么就没有关系了
  • 当由于某种未知原因,10 秒后,连接没有返回任何内容,并且此行也会发生,仅此而已。这似乎是一个超时,但我不确定(因为我的 WebClient 配置中的默认超时是 10 秒)

这可能是什么原因造成的?客户端主动掉线还是服务器主动拒绝?

第二种情况是超时吗?但TimeoutException()之后不会被抛出。

我现在doOnCancel()在 WebClient 中进行日志记录来处理第二种情况,但后来我注意到存在情况 1,并且这种doOnCancel()处理不再有意义,因为它似乎在所有情况下都会发生。

reactor-netty spring-webflux spring-webclient

5
推荐指数
1
解决办法
3455
查看次数

如何在 Spring WebClient 请求之间保存 cookie?

我想在我的项目中使用 Spring Boot WebClient 来访问 REST-API。第一个请求执行 REST-API 登录并接收 cookie 作为响应。此 cookie 用作所有其他请求的“API 令牌”。

然而,WebClient似乎不存储cookie。我必须自己做吗?如果是这样,最好的方法是什么?

以下是我的示例源代码。第二个请求不使用第一个请求的 cookie。

// ### 1. API-Call to get the cookie ###
ClientResponse clientResponse = webClient
        .get()
        .uri("/api/")
        .headers(headers -> headers.setBasicAuth(user,passwd)
        .exchange()
        .block();

// ### Debug Cookie ###
if (clientResponse.statusCode().is2xxSuccessful()) {
    for (String key : clientResponse.cookies().keySet()) {
        LOG.debug("key:" + key + " value: " + clientResponse.cookies().get(key).get(0).getValue() );
    }
}   

// ### 2.API-Call (with cookie) ###
webClient
    .get()
    .uri("/api/document/4711")
    .retrieve()
    .onStatus(HttpStatus::is2xxSuccessful, r -> {
        for (String key : …
Run Code Online (Sandbox Code Playgroud)

spring spring-boot spring-webflux spring-webclient

5
推荐指数
1
解决办法
4037
查看次数

BodyInserters.fromObject 已弃用,替代方案是什么?

你好。我正在尝试使用 Spring webclient 发送 post 请求并用对象填充主体。但我收到以下“‘fromObject(T)’已弃用”。那么还有什么选择呢?

WebClient.post()
            .uri("example.com")
            .body(BodyInserters.fromObject(newObject);
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webclient

5
推荐指数
1
解决办法
4919
查看次数

Spring Boot WebClient 连接和读取超时

目前,我的 post 和 get 请求是通过 WebClients 处理的,WebClients 在 Spring Boot 中具有公共连接和读取超时。我有 5 个不同的类,每个类都需要自己的一组连接和读取超时。我不想创建 5 个不同的 WebClient,而是使用相同的 Webclient,但在从特定类发送 post 或 get 请求时,指定所需的连接和读取超时。有没有办法实现这个?

我当前的网络客户端:

    @Bean
    public WebClient getWebClient(WebClient.Builder builder){

        HttpClient httpClient = HttpClient.newConnection()
                .tcpConfiguration(tcpClient -> {
                    tcpClient = tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout*1000);
                    tcpClient = tcpClient.doOnConnected(conn -> conn
                            .addHandlerLast(new ReadTimeoutHandler(readTimeout, TimeUnit.SECONDS)));
                    return tcpClient;
                }).wiretap(true);

        ClientHttpConnector connector = new ReactorClientHttpConnector(httpClient);

        return builder.clientConnector(connector).build();
    }
Run Code Online (Sandbox Code Playgroud)

我正在使用的帖子请求:

public WebClientResponse httpPost(String endpoint, String requestData, Map<String, Object> requestHeader) {

        ClientResponse res = webClient.post().uri(endpoint)
                .body(BodyInserters.fromObject(requestData))
                .headers(x -> {
                    if(requestHeader != null && …
Run Code Online (Sandbox Code Playgroud)

java spring-boot spring-webclient

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

如何使用 UriBuilder 构建 URI,而不单独指定方案、主机?

参考:org.springframework.web.util.UriBuilder

我正在用来UriBuilder为端点构建 URI

final String response = myWebClient.get()
   .uri(uriBuilder -> uriBuilder.scheme("https").path("example.com/mypage").path("/{id}.xml").build(id))
   .header(AUTHORIZATION, getAuthorizationHeaderValue(username, password))
   .accept(MediaType.TEXT_XML)
   .retrieve()
   .bodyToMono(String.class)
   .block();
Run Code Online (Sandbox Code Playgroud)

但是,我已经在字符串变量中获得了值https://example.com/mypage(从数据库中获取)。我可以直接使用这个字符串而不是单独指定方案和路径/主机吗?现在我正在手动将主字符串分成单独的部分。

uri uribuilder spring-boot spring-webflux spring-webclient

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