11.4 响应式地消费REST API
11.4 响应式地消费REST API
在第
但是
如果有一种方法可以将
使用
- 创建一个
WebClient 实例(或是注入一个WebClient bean ) - 指定用于发送请求的
HTTP 方法 - 指定
URI 和应该存在于请求中Header - 提交请求
- 获取响应
让我们看看
11.4.1 GET 资源
作为
Mono<Ingredient> ingredient = WebClient.create().get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Ingredient.class);
ingredient.subscribe(i -> { ... })
在这里,将使用http://localhost:8080/ingresents/{id}
的{id}
占位符将替换为
要对
Flux<Ingredient> ingredients = WebClient.create()
.get()
.uri("http://localhost:8080/ingredients")
.retrieve()
.bodyToFlux(Ingredient.class);
ingredients.subscribe(i -> { ... })
对于大多数情况,获取多条数据与请求单个数据一样。最大的区别在于,你不用
和
使用一个基本
你可能会发现,自己对许多不同的请求都使用一个通用的基本
@Bean
public WebClient webClient() {
return WebClient.create("http://localhost:8080");
}
然后,在需要使用该基本
@Autowired
WebClient webClient;
public Mono<Ingredient> getIngredientById(String ingredientId) {
Mono<Ingredient> ingredient = webClient
.get()
.uri("/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Ingredient.class);
ingredient.subscribe(i -> { ... })
}
因为
对长期运行的请求的定时处理
你可以指望的是,网络并不总是像你期望的那样可靠和快速。或者,远程服务器在处理请求时可能很慢。理想情况下,对远程服务的请求将在合理的时间内返回。如果不是,如果客户没有长时间等待响应,那已经非常值得庆幸了。
为了避免客户端请求被缓慢的网络或服务所阻塞,可以使用
Flux<Ingredient> ingredients = WebClient.create()
.get()
.uri("http://localhost:8080/ingredients")
.retrieve()
.bodyToFlux(Ingredient.class);
ingredients
.timeout(Duration.ofSeconds(1))
.subscribe(
i -> { ... },
e -> {
// handle timeout error
})
在订阅
11.4.2 发送资源
使用
只需使用
Mono<Ingredient> ingredientMono = ...;
Mono<Ingredient> result = webClient
.post()
.uri("/ingredients")
.body(ingredientMono, Ingredient.class)
.retrieve()
.bodyToMono(Ingredient.class);
result.subscribe(i -> { ... })
如果没有
Ingedient ingredient = ...;
Mono<Ingredient> result = webClient
.post()
.uri("/ingredients")
.syncBody(ingredient)
.retrieve()
.bodyToMono(Ingredient.class);
result.subscribe(i -> { ... })
如果你想要用
Mono<Void> result = webClient
.put()
.uri("/ingredients/{id}", ingredient.getId())
.syncBody(ingredient)
.retrieve()
.bodyToMono(Void.class)
.subscribe();
11.4.3 删除资源
Mono<Void> result = webClient
.delete()
.uri("/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Void.class)
.subscribe();
与
11.4.4 处理错误
到目前为止,所有的
如果你需要处理此类错误,那么可以使用对
为了演示如何使用
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Ingredient.class);
只要
当订阅一个可能以错误结束的
ingredientMono.subscribe(
ingredient -> {
// handle the ingredient data
...
},
error-> {
// deal with the error
...
});
如果找到该成分资源,那么将调用给予
通过添加自定义错误处理程序,可以提供将状态代码转换为自己选择的
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.onStatus(HttpStatus::is4xxClientError,
response -> Mono.just(new UnknownIngredientException()))
.bodyToMono(Ingredient.class);
在示例中,如果状态码是
注意
例如,可以通过将调用更改为
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.onStatus(status -> status == HttpStatus.NOT_FOUND,
response -> Mono.just(new UnknownIngredientException()))
.bodyToMono(Ingredient.class);
同样值得一提的是,在处理响应中可能返回的任何
11.4.5 交换请求
到目前为止,在使用
当
在我们研究
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.exchange()
.flatMap(cr -> cr.bodyToMono(Ingredient.class));
这大致相当于下面的使用
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.retrieve()
.bodyToMono(Ingredient.class);
在
现在让我们来看看
Mono<Ingredient> ingredientMono = webClient
.get()
.uri("http://localhost:8080/ingredients/{id}", ingredientId)
.exchange()
.flatMap(cr -> {
if (cr.headers().header("X_UNAVAILABLE").contains("true")) {
return Mono.empty();
}
return Mono.just(cr);
})
.flatMap(cr -> cr.bodyToMono(Ingredient.class));
新的