如何从Spring 5 WebClient ClientResponse中提取响应标头和状态代码

Ren*_*s11 6 spring spring-boot spring-webflux

我是Spring Reactive框架的新手,正在尝试将Springboot 1.5.x代码转换为Springboot 2.0。在Spring 5 WebClient ClientResponse中进行一些过滤,正文和状态代码后,我需要返回响应头。我不想使用block()方法,因为它将将其转换为同步调用。我可以使用bodyToMono轻松获得responsebody。另外,如果我只是返回ClientResponse,我会得到状态代码,标头和正文,但是我需要根据statusCode和标头参数处理响应。我尝试了订阅,flatMap等,但是没有任何效果。

例如-以下代码将返回响应正文

Mono<String> responseBody =  response.flatMap(resp -> resp.bodyToMono(String.class));
Run Code Online (Sandbox Code Playgroud)

但是类似的范例无法获取statusCode和Response标头。有人可以帮助我使用Spring 5反应性框架提取statusCode和标头参数。

Kev*_*sey 20

您可以使用 webclient 的交换功能,例如

Mono<String> reponse = webclient.get()
.uri("https://stackoverflow.com")
.exchange()
.doOnSuccess(clientResponse -> System.out.println("clientResponse.headers() = " + clientResponse.headers()))
.doOnSuccess(clientResponse -> System.out.println("clientResponse.statusCode() = " + clientResponse.statusCode()))
.flatMap(clientResponse -> clientResponse.bodyToMono(String.class));
Run Code Online (Sandbox Code Playgroud)

然后你可以转换 bodyToMono 等

  • 但这只是打印 HttpStatus 代码。如果我需要返回它的值怎么办?这可能吗? (5认同)

小智 20

在 Spring Boot 2.4.x / Spring 5.3 之后,exchange不推荐使用 WebClient 方法retrieve,而是使用 ResponseEntity 方法,因此您必须使用 ResponseEntity 获取标头和响应状态,如下例所示:

webClient
        .method(HttpMethod.POST)
        .uri(uriBuilder -> uriBuilder.path(loginUrl).build())
        .bodyValue(new LoginBO(user, passwd))
        .retrieve()
        .toEntity(LoginResponse.class)
        .filter(
            entity ->
                entity.getStatusCode().is2xxSuccessful()
                    && entity.getBody() != null
                    && entity.getBody().isLogin())
        .flatMap(entity -> Mono.justOrEmpty(entity.getHeaders().getFirst(tokenHeader)));
Run Code Online (Sandbox Code Playgroud)


小智 14

我还需要检查响应详细信息(标题、状态等)和正文。

我能够做到这一点的唯一方法是使用.exchange()两个subscribe()作为以下示例:

    Mono<ClientResponse> clientResponse = WebClient.builder().build()
            .get().uri("https://stackoverflow.com")
            .exchange();

    clientResponse.subscribe((response) -> {

        // here you can access headers and status code
        Headers headers = response.headers();
        HttpStatus stausCode = response.statusCode();

        Mono<String> bodyToMono = response.bodyToMono(String.class);
        // the second subscribe to access the body
        bodyToMono.subscribe((body) -> {

            // here you can access the body
            System.out.println("body:" + body);

            // and you can also access headers and status code if you need
            System.out.println("headers:" + headers.asHttpHeaders());
            System.out.println("stausCode:" + stausCode);

        }, (ex) -> {
            // handle error
        });
    }, (ex) -> {
        // handle network error
    });
Run Code Online (Sandbox Code Playgroud)

我希望它有帮助。如果有人知道更好的方法,请告诉我们。


Ath*_*har 9

如上所述,交换已被弃用,因此我们使用retrieve()。这就是我在发出请求后返回代码的方式。

public HttpStatus getResult() {
    WebClient.ResponseSpec response = client
            .get()
            .uri("/hello")
            .accept(MediaType.APPLICATION_JSON)
            .retrieve();

    return Optional.of(response.toBodilessEntity().block().getStatusCode()).get();
}
Run Code Online (Sandbox Code Playgroud)

根据评论,我最近尝试过另一种选择。通常建议将其用于异步调用,但我们可以将其用于两者。

MyClass responseMono = this.webClient
                .get()
                .uri("myapipath")
                .retrieve()
                .bodyToMono(MyClass.class)
                .block();
        return responseMono;
Run Code Online (Sandbox Code Playgroud)


jcr*_*ada 6

 httpClient
            .get()
            .uri(url)
            .retrieve()
            .toBodilessEntity()
            .map(reponse -> Tuple2(reponse.statusCode, reponse.headers))
Run Code Online (Sandbox Code Playgroud)


Shr*_*rma 5

对于状态代码,您可以尝试以下操作:

Mono<HttpStatus> status = webClient.get()
                .uri("/example")
                .exchange()
                .map(response -> response.statusCode());
Run Code Online (Sandbox Code Playgroud)

对于标题:

Mono<HttpHeaders> result = webClient.get()
                .uri("/example")
                .exchange()
                .map(response -> response.headers().asHttpHeaders());
Run Code Online (Sandbox Code Playgroud)

  • 如何打印“状态”值?就像“200”而不是整个 Mono&lt;&gt; 对象 (2认同)