1. 概述

在处理HTTP响应时,通常会利用响应的状态码来决定应用程序接下来如何处理给定的响应。本教程将介绍如何使用Spring WebFlux的WebClient来访问REST请求返回的状态码和响应体。

WebClient是Spring 5引入的功能,用于异步I/O调用RESTful服务。

2. 使用场景

当应用程序向其他服务发起RESTful调用时,通常会根据返回的状态码(状态码)触发不同的功能。常见的应用场景包括优雅地处理错误、重试请求以及确定用户错误。

因此,在进行REST调用时,仅仅获取响应代码通常是不够的,有时我们还需要响应体。下面的例子将展示如何从REST客户端WebClient解析响应体,并将行为与返回的状态码关联起来,利用WebClient提供的两种状态码提取方法:onStatusExchangeFilterFunction

3. 使用onStatus

onStatusWebClient内置的一种机制,可用于处理响应。它允许我们基于特定的状态码(如400、500、503等)或类别(如4xx和5xx等)应用精细粒度的功能:

WebClient
  .builder()
  .build()
  .post()
  .uri("/some-resource")
  .retrieve()
  .onStatus(
    HttpStatus.INTERNAL_SERVER_ERROR::equals,
    response -> response.bodyToMono(String.class).map(Exception::new))

onStatus方法需要两个参数:一个接受状态码的谓词,另一个根据第一个参数的结果执行。第二个参数是一个将响应映射到Mono或异常的函数。

在这种情况下,如果遇到INTERNAL_SERVER_ERROR(即500),我们将使用bodyToMono获取响应体,并将其映射为一个新的异常。

我们可以链式调用onStatus以针对不同状态条件提供功能:

Mono<String> response = WebClient
  .builder()
  .build()
  .post()
  .uri("some-resource")
  .retrieve()
  .onStatus( 
    HttpStatus.INTERNAL_SERVER_ERROR::equals,
    response -> response.bodyToMono(String.class).map(CustomServerErrorException::new)) 
  .onStatus(
    HttpStatus.BAD_REQUEST::equals,
    response -> response.bodyToMono(String.class).map(CustomBadRequestException::new))
  ... 
  .bodyToMono(String.class);

// do something with response

现在,onStatus调用将映射到我们的自定义异常类型。我们为每个错误状态定义了异常类型。onStatus方法允许我们选择任何类型的异常。

4. 使用ExchangeFilterFunction

ExchangeFilterFunction是另一种处理特定状态码并获取响应体的方法。与onStatus不同,过滤器更为灵活,可以根据任何布尔表达式应用功能。

我们可以利用ExchangeFilterFunction的灵活性,覆盖与onStatus相同的功能类别

首先,我们定义一个方法,根据给定的状态码处理返回逻辑,基于ClientResponse

private static Mono<ClientResponse> exchangeFilterResponseProcessor(ClientResponse response) {
    HttpStatusCode status = response.statusCode();
    if (HttpStatus.INTERNAL_SERVER_ERROR.equals(status)) {
        return response.bodyToMono(String.class)
          .flatMap(body -> Mono.error(new CustomServerErrorException(body)));
    }
    if (HttpStatus.BAD_REQUEST.equals(status)) {
        return response.bodyToMono(String.class)
          .flatMap(body -> Mono.error(new CustomBadRequestException(body)));
    }
    return Mono.just(response);
}

接下来,我们将定义过滤器并使用方法引用指向我们的处理器:

ExchangeFilterFunction errorResponseFilter = ExchangeFilterFunction
  .ofResponseProcessor(WebClientStatusCodeHandler::exchangeFilterResponseProcessor);

类似地,我们在错误时将Exception类型映射到我们的异常。然而,使用Mono.error将这个异常封装在ReactiveException中。在处理错误时,要注意这种嵌套(处理错误)。

现在,我们将将此应用于WebClient实例,以实现与onStatus链式调用相同的效果

Mono<String> response = WebClient
  .builder()
  .filter(errorResponseFilter)
  .build()
  .post()
  .uri("some-resource")
  .retrieve()
  .bodyToMono(String.class);

// do something with response

5. 总结

在这篇文章中,我们探讨了几种根据HTTP状态头获取响应体的方法。onStatus方法允许我们根据状态码插入选定功能。此外,我们还可以使用过滤器方法插入通用方法,以处理所有响应的后处理。

如往常一样,本文的所有代码可以在GitHub上找到