如何处理webclient抛出的异常?

Tra*_*ace 5 spring-boot spring-webflux

我试图弄清楚如何从 webclient 记录异常,无论从被调用的 api 返回的错误状态代码是什么。

我已经看到了以下实现:

.onStatus(status -> status.value() != HttpStatus.OK.value(),
            rs -> rs.bodyToMono(String.class).map(body -> new IOException(String.format(
                "Response HTTP code is different from 200: %s, body: '%s'", rs.statusCode(), body))))
Run Code Online (Sandbox Code Playgroud)

我见过的另一个例子使用过滤器。我想这个过滤器也可以用来记录错误,除了这个例子中的请求:

public MyClient(WebClient.Builder webClientBuilder) {
    webClient = webClientBuilder // you can also just use WebClient.builder()
            .baseUrl("https://httpbin.org")
            .filter(logRequest()) // here is the magic
            .build();
}
Run Code Online (Sandbox Code Playgroud)

但是我们是否认真地认为这件事没有专门的异常处理程序?

Tra*_*ace 4

找到了。
bodyToMono如果状态代码为 4xx(客户端错误)或 5xx(服务器错误),则抛出 WebClientException。

全面实施服务:

@Service
public class FacebookService {
    private static final Logger LOG = LoggerFactory.getLogger(FacebookService.class);
    private static final String URL_DEBUG = "https://graph.facebook.com/debug_token";
    private WebClient webClient;

    public FacebookService() {
        webClient = WebClient.builder()
                .filter(logRequest())
                .build();
    }

    public Mono<DebugTokenResponse> verifyFbAccessToken(String fbAccessToken, String fbAppToken) {
        LOG.info("verifyFacebookToken for " + String.format("fbAccessToken: %s and fbAppToken: %s", fbAccessToken, fbAppToken));
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(URL_DEBUG)
                .queryParam("input_token", fbAccessToken)
                .queryParam("access_token", fbAppToken);
        return this.webClient.get()
                .uri(builder.toUriString())
                .retrieve()
                .bodyToMono(DebugTokenResponse.class);
    }

    private static ExchangeFilterFunction logRequest() {
        return ExchangeFilterFunction.ofRequestProcessor(clientRequest -> {
            LOG.info("Request: {} {}", clientRequest.method(), clientRequest.url());
            clientRequest.headers().forEach((name, values) -> values.forEach(value -> LOG.info("{}={}", name, value)));
            return Mono.just(clientRequest);
        });
    }

    @ExceptionHandler(WebClientResponseException.class)
    public ResponseEntity<String> handleWebClientResponseException(WebClientResponseException ex) {
        LOG.error("Error from WebClient - Status {}, Body {}", ex.getRawStatusCode(), ex.getResponseBodyAsString(), ex);
        return ResponseEntity.status(ex.getRawStatusCode()).body(ex.getResponseBodyAsString());
    }
}
Run Code Online (Sandbox Code Playgroud)