将 exchange() 与 Spring WebClient 一起使用时如何抛出 WebClientResponseException
How to throw WebClientResponseException when using exchange() with Spring WebClient
当结合使用 Spring WebClient 的 retrieve() 方法和 bodyToMono 默认错误处理时(如果响应的状态代码为 4xx 或 5xx,Mono 将包含 WebClientException)。在错误情况下,生成的 WebClientException 非常有用,因为它包含请求和响应,这非常方便,例如用于记录。此外,我可以很好地对错误做出反应。
/*
* Easy to use retrieve() with default error handling:
* By default, if the response has status code 4xx or 5xx, the Mono will contain a WebClientException - AWESOME!
*/
public Optional<MyType> getMyType() {
try {
MyType result = client
.get()
.uri("/myType")
.retrieve().bodyToMono(MyType.class).block();
return Optional.ofNullable(result);
} catch (NotFound e) {
return Optional.empty();
}
}
但是,有时我需要知道响应的确切状态代码,以便在进一步处理此响应时对其做出反应。同时获取状态代码的唯一方法是调用 exchange() 方法而不是 retrieve() 方法。不幸的是,在那种情况下,默认的错误处理不会被应用。原因似乎是在 ClientResponse 上调用 bodyToMono() 与在 ResponseSpec 上调用它具有不同的语义。
我无法调用从 Spring 到 "trigger" 的已经实现的方法进行错误处理,因为所有好的方法都作为私有方法隐藏在 WebClient 中。
即使我尝试 "manually" 创建 WebClientResponseException 我也做不到
访问请求以提供异常。
public String updateMyType() {
ClientResponse response = client
.put()
.uri("/myType")
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.body(fromObject(new MyType()))
.exchange()
.block();
if (response.statusCode().equals(HttpStatus.CREATED)) {
return "OK";
} else if (response.statusCode().equals(HttpStatus.NO_CONTENT)) {
return "updated";
} else {
byte[] bodyBytes = null; // already implemented by Sping but not accessible
Charset charset = null; // already implemented by Sping but not accessible
HttpRequest request = null; // where should I get this from?
throw WebClientResponseException.create(response.statusCode().value(),
response.statusCode().getReasonPhrase(),
response.headers().asHttpHeaders(),
bodyBytes,
charset,
request);
}
}
“模仿”与 retrieve() 方法相同行为的最佳方法是什么?
回答问题时可能不是这种情况,但由于 Spring 5.2,ClientResponse
有一个 createException()
方法可以构建并且 return Mono<WebClientResponseException>
.
clientResponse.createException()
.flatMap(e -> handleException(e))
https://github.com/spring-projects/spring-framework/commit/b4207823afa0f48e06d6bbfe9ae8821e389e380f
当结合使用 Spring WebClient 的 retrieve() 方法和 bodyToMono 默认错误处理时(如果响应的状态代码为 4xx 或 5xx,Mono 将包含 WebClientException)。在错误情况下,生成的 WebClientException 非常有用,因为它包含请求和响应,这非常方便,例如用于记录。此外,我可以很好地对错误做出反应。
/*
* Easy to use retrieve() with default error handling:
* By default, if the response has status code 4xx or 5xx, the Mono will contain a WebClientException - AWESOME!
*/
public Optional<MyType> getMyType() {
try {
MyType result = client
.get()
.uri("/myType")
.retrieve().bodyToMono(MyType.class).block();
return Optional.ofNullable(result);
} catch (NotFound e) {
return Optional.empty();
}
}
但是,有时我需要知道响应的确切状态代码,以便在进一步处理此响应时对其做出反应。同时获取状态代码的唯一方法是调用 exchange() 方法而不是 retrieve() 方法。不幸的是,在那种情况下,默认的错误处理不会被应用。原因似乎是在 ClientResponse 上调用 bodyToMono() 与在 ResponseSpec 上调用它具有不同的语义。
我无法调用从 Spring 到 "trigger" 的已经实现的方法进行错误处理,因为所有好的方法都作为私有方法隐藏在 WebClient 中。
即使我尝试 "manually" 创建 WebClientResponseException 我也做不到 访问请求以提供异常。
public String updateMyType() {
ClientResponse response = client
.put()
.uri("/myType")
.header(CONTENT_TYPE, APPLICATION_JSON_VALUE)
.body(fromObject(new MyType()))
.exchange()
.block();
if (response.statusCode().equals(HttpStatus.CREATED)) {
return "OK";
} else if (response.statusCode().equals(HttpStatus.NO_CONTENT)) {
return "updated";
} else {
byte[] bodyBytes = null; // already implemented by Sping but not accessible
Charset charset = null; // already implemented by Sping but not accessible
HttpRequest request = null; // where should I get this from?
throw WebClientResponseException.create(response.statusCode().value(),
response.statusCode().getReasonPhrase(),
response.headers().asHttpHeaders(),
bodyBytes,
charset,
request);
}
}
“模仿”与 retrieve() 方法相同行为的最佳方法是什么?
回答问题时可能不是这种情况,但由于 Spring 5.2,ClientResponse
有一个 createException()
方法可以构建并且 return Mono<WebClientResponseException>
.
clientResponse.createException()
.flatMap(e -> handleException(e))
https://github.com/spring-projects/spring-framework/commit/b4207823afa0f48e06d6bbfe9ae8821e389e380f