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

q3aa0525  于 2023-02-07  发布在  Java
关注(0)|答案(9)|浏览(447)

我是Spring Reactive框架的新手,正在尝试将Springboot 1.5.x代码转换为Springboot 2.0。我需要在经过一些过滤后返回响应头、主体和来自Spring 5 WebClient ClientResponse的状态代码。我不想使用块()方法,因为它会将其转换为同步调用。我可以很容易地使用bodyToMono获得responsebody。此外,我正在获得状态代码,header & body,如果我只是返回ClientResponse,但我需要根据statusCode & header参数处理响应。我尝试了subscribe,flatMap等,但没有任何效果。
例如-以下代码将返回响应Body

Mono<String> responseBody =  response.flatMap(resp -> resp.bodyToMono(String.class));

但是类似的范例在获取statusCode和响应头时不起作用。有人能帮我使用Spring 5React式框架提取statusCode和响应头参数吗?

jv2fixgn

jv2fixgn1#

您可以使用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));

然后你可以将bodyToMono等

kt06eoxx

kt06eoxx2#

我需要检查响应的细节(头,状态等)和身体以及。
我能够做到这一点的唯一方法是使用.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
    });

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

6yt4nkrj

6yt4nkrj3#

在Sping Boot 2.4.x / Spring 5.3之后,WebClient exchange方法被弃用,取而代之的是retrieve,因此您必须使用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)));
rekjcdws

rekjcdws4#

如上所述,exchange已经过时了,所以我们使用retrieve(),这就是我在发出请求后返回代码的方式。

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

    return Optional.of(response.toBodilessEntity().block().getStatusCode()).get();
}

另一个选项,根据评论,我最近尝试过。这通常是建议异步调用,但我们可以使用它的两个。

MyClass responseMono = this.webClient
                .get()
                .uri("myapipath"}")
                .retrieve()
                .bodyToMono(MyClass.class)
                .block();
        return responseMono;
lh80um4z

lh80um4z5#

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

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

对于标题:

Mono<HttpHeaders> result = webClient.get()
                .uri("/example")
                .exchange()
                .map(response -> response.headers().asHttpHeaders());
rfbsl7qr

rfbsl7qr6#

如果使用WebClient,您可以配置spring Boot 〉= 2.1.0来记录请求和响应:

spring.http.log-request-details: true
logging.level.org.springframework.web.reactive.function.client.ExchangeFunctions: TRACE

正如sprint Boot 文档中所描述的,如果您还希望记录头文件,则必须添加

Consumer<ClientCodecConfigurer> consumer = configurer ->
    configurer.defaultCodecs().enableLoggingRequestDetails(true);

WebClient webClient = WebClient.builder()
    .exchangeStrategies(ExchangeStrategies.builder().codecs(consumer).build())
    .build();

但要注意,这可能会记录敏感信息。

ha5z0ras

ha5z0ras7#

httpClient
            .get()
            .uri(url)
            .retrieve()
            .toBodilessEntity()
            .map(reponse -> Tuple2(reponse.statusCode, reponse.headers))
rks48beu

rks48beu8#

可以使用flatMapMono中提取对象

egmofgnx

egmofgnx9#

以MAP形式发送请求以MAP形式获取响应检查过滤器功能中的所有状态代码

private static Mono<ClientResponse>  filterFunc(ClientResponse response) {
        HttpStatus status = response.statusCode();
        if (HttpStatus.BAD_REQUEST.equals(status)) {
            return response.bodyToMono(String.class)
                    .flatMap(body -> Mono.error(new MyCustomHttpErrorException(  HttpStatus.BAD_REQUEST ,  body) ));
        } else if (!HttpStatus.OK.equals(status)) {
            return response.bodyToMono(String.class)
                    .flatMap(body -> Mono.error(  new MyCustomHttpErrorException(  status ,  body) )); 
        }

       return Mono.just(response);
    }

  this.webClient = builder.baseUrl(serverUrl)
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                .filter(ExchangeFilterFunction.ofResponseProcessor(MyClass::exchangeFilterResponseProcessor))  
                .build();

   Mono<Map<String, String>> mnoObjStream;
        mnoObjStream = webClient.post().uri("/abc")
                .body(BodyInserters
                        .fromFormData("key1","val1").with("key2","val2").with("key3","val3"))
                        .retrieve()  // Note use retrieve  because  exchange() has been deprecated.
                .bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {});  
        resp = mnoObjStream.block();

相关问题