WebClient是Spring 5中新引入的一個(gè)接口基于響應(yīng)式,它提供了" />
Spring 6是一個(gè)非常強(qiáng)大的框架,它提供了許多工具和接口來簡化遠(yuǎn)程接口調(diào)用。其中,WebClient、RestTemplate、HTTP Interface和RestClient是四種方式。
WebClient是Spring 5中新引入的一個(gè)接口基于響應(yīng)式,它提供了一種更簡單、更靈活的方式來調(diào)用遠(yuǎn)程接口。與RestTemplate相比,WebClient更加現(xiàn)代化,具有更好的性能和更低的內(nèi)存占用。
RestTemplate是Spring 3中引入的一個(gè)接口,它提供了一種更加簡單、更加直觀的方式來調(diào)用遠(yuǎn)程接口。雖然WebClient是更現(xiàn)代化的選擇,但RestTemplate仍然是一種常用的遠(yuǎn)程接口調(diào)用方式。
HTTP Interface將 HTTP 服務(wù)定義為一個(gè) Java 接口,其中包含用于 HTTP 交換的注解方法。然后,你可以生成一個(gè)實(shí)現(xiàn)該接口并執(zhí)行交換的代理。這有助于簡化 HTTP 遠(yuǎn)程訪問,因?yàn)檫h(yuǎn)程訪問通常需要使用一個(gè)門面來封裝使用底層 HTTP 客戶端的細(xì)節(jié)。
RestClient是一個(gè)同步 HTTP 客戶端,提供現(xiàn)代、流暢的 API。它為 HTTP 庫提供了一個(gè)抽象,可以方便地從 Java 對(duì)象轉(zhuǎn)換為 HTTP 請(qǐng)求,并從 HTTP 響應(yīng)創(chuàng)建對(duì)象。
下面分別介紹4個(gè)REST接口調(diào)用的詳細(xì)使用。
RestTemplate 提供了比 HTTP 客戶端庫更高級(jí)別的 API。它使調(diào)用 REST 端點(diǎn)變得簡單易行。它公開了以下幾組重載方法:
方法 | 描述 |
getForObject | 通過GET檢索數(shù)據(jù)。 |
getForEntity | 使用 GET 獲取響應(yīng)實(shí)體(即狀態(tài)、標(biāo)頭和正文)。 |
headForHeaders | 使用 HEAD 讀取資源的所有標(biāo)頭。 |
postForLocation | 使用 POST 創(chuàng)建新資源,并從響應(yīng)中返回位置標(biāo)頭。 |
postForObject | 使用 POST 創(chuàng)建一個(gè)新資源,并從響應(yīng)中返回描述。 |
postForEntity | 使用 POST 創(chuàng)建一個(gè)新資源,并從響應(yīng)中返回描述。 |
put | 使用 PUT 創(chuàng)建或更新資源。 |
patchForObject | 使用 PATCH 更新資源,并返回響應(yīng)中的描述。請(qǐng)注意,JDK HttpURLConnection 不支持 PATCH,但 Apache HttpComponents 和其他組件支持。 |
delete | 使用 DELETE 刪除指定 URI 上的資源。 |
optionsForAllow | 通過 ALLOW 讀取資源允許使用的 HTTP 方法。 |
exchange | 前述方法的更通用(更少意見)版本,可在需要時(shí)提供額外的靈活性。它接受一個(gè) RequestEntity(包括作為輸入的 HTTP 方法、URL、標(biāo)題和正文),并返回一個(gè) ResponseEntity。 這些方法允許使用參數(shù)化類型引用(ParameterizedTypeReference)而不是類(Class)來指定具有泛型的響應(yīng)類型。 |
execute | 執(zhí)行請(qǐng)求的最通用方式,可通過回調(diào)接口完全控制請(qǐng)求準(zhǔn)備和響應(yīng)提取。 |
默認(rèn)構(gòu)造函數(shù)使用 java.net.HttpURLConnection 來執(zhí)行請(qǐng)求。你可以通過 ClientHttpRequestFactory 的實(shí)現(xiàn)切換到不同的 HTTP 庫。目前,該程序還內(nèi)置了對(duì) Apache HttpComponents 和 OkHttp 的支持。示例:
RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
每個(gè) ClientHttpRequestFactory 都會(huì)公開底層 HTTP 客戶端庫的特定配置選項(xiàng),例如,憑證、連接池和其他細(xì)節(jié)。
許多 RestTemplate 方法都接受 URI 模板和 URI 模板變量,可以是字符串變量參數(shù),也可以是 Map<String,String>。
String result = restTemplate.getForObject( "http://pack.com/users/{userId}", String.class, 666) ;
Map<String, ?>方式:
Map<String, Object> params = Collections.singletonMap("userId", 666);String result = restTemplate.getForObject( "http://pack.com/users/{userId}", String.class, params) ;
可以使用 exchange() 方法指定請(qǐng)求頭,如下例所示:
String uriTemplate = "http://pack.com/users/{userId}";URI uri = UriComponentsBuilder.fromUriString(uriTemplate).build(42);RequestEntity<Void> requestEntity = RequestEntity.get(uri) .header("x-api-token", "aabbcc") .build() ;ResponseEntity<String> response = template.exchange(requestEntity, String.class);String responseHeader = response.getHeaders().getFirst("x-version");String body = response.getBody() ;
如果你當(dāng)前CLASSPATH存在MappingJackson2HttpMessageConverter,那么你可以直接將請(qǐng)求結(jié)果映射為你所需要的結(jié)果對(duì)象,如下示例所示,將目標(biāo)接口返回值直接轉(zhuǎn)換為User對(duì)象。
User user = restTemplate.getForObject("http://pack.com/users/{userId}", User.class, 666);
默認(rèn)情況下,RestTemplate 會(huì)注冊(cè)所有內(nèi)置的消息轉(zhuǎn)換器,這決定于你當(dāng)前類路徑是否有相應(yīng)的轉(zhuǎn)換庫。你也可以顯式設(shè)置要使用的消息轉(zhuǎn)換器。默認(rèn)構(gòu)造函數(shù)如下:
public RestTemplate() { this.messageConverters.add(new ByteArrayHttpMessageConverter()); this.messageConverters.add(new StringHttpMessageConverter()); this.messageConverters.add(new ResourceHttpMessageConverter(false)); // ...其它轉(zhuǎn)換器 if (jackson2Present) { this.messageConverters.add(new MappingJackson2HttpMessageConverter()); } else if (gsonPresent) { this.messageConverters.add(new GsonHttpMessageConverter()); } else if (jsonbPresent) { this.messageConverters.add(new JsonbHttpMessageConverter()); } // ...其它轉(zhuǎn)換器 this.uriTemplateHandler = initUriTemplateHandler();}
注意:RestTemplate 目前處于維護(hù)模式,只接受小改動(dòng)和錯(cuò)誤請(qǐng)求。請(qǐng)考慮改用 WebClient。
WebClient 是執(zhí)行 HTTP 請(qǐng)求的非阻塞、反應(yīng)式客戶端。它在 5.0 中引入,提供了 RestTemplate 的替代方案,支持同步、異步和流場(chǎng)景。
WebClient 支持以下功能:
示例:
Mono<Person> result = client.get() .uri("/users/{userId}", id).accept(MediaType.APPLICATION_JSON) .retrieve() .bodyToMono(User.class);
Spring Framework 可讓你將 HTTP 服務(wù)定義為一個(gè) Java 接口,其中包含用于 HTTP 交換的注解方法。然后,你可以生成一個(gè)實(shí)現(xiàn)該接口并執(zhí)行交換的代理。這有助于簡化 HTTP 遠(yuǎn)程訪問,因?yàn)檫h(yuǎn)程訪問通常需要使用一個(gè)門面來封裝使用底層 HTTP 客戶端的細(xì)節(jié)。
首先,聲明一個(gè)帶有 @HttpExchange 方法的接口:
@HttpExchange(url = "/demos")public interface DemoInterface { @PostExchange("/format3/{id}") Users queryUser(@PathVariable Long id);}
創(chuàng)建一個(gè)代理,執(zhí)行所聲明的 HTTP exchanges:
@Servicepublic class DemoService { private final DemoInterface demoInterface ; public DemoService() { // 基于響應(yīng)式調(diào)用;你當(dāng)前的環(huán)境需要引入webflux WebClient client = WebClient.builder().baseUrl("http://localhost:8088/").build() ; HttpServiceProxyFactory factory = HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)).build() ; this.demoInterface = factory.createClient(DemoInterface.class) ; } public Users queryUser(Long id) { return this.demoInterface.queryUser(id) ; }}
測(cè)試接口
@Resourceprivate DemoService demoService ;@GetMapping("/{id}")public Users getUser(@PathVariable("id") Long id) { return this.demoService.queryUser(id) ;}
執(zhí)行結(jié)果
圖片
支持的方法參數(shù)
方法參數(shù) | 說明 |
URI | 動(dòng)態(tài)設(shè)置請(qǐng)求的 URL,覆蓋注解的 url 屬性。 |
HttpMethod | 動(dòng)態(tài)設(shè)置請(qǐng)求的 HTTP 方法,覆蓋注解的方法屬性 |
@RequestHeader | 添加一個(gè)或多個(gè)請(qǐng)求標(biāo)頭。參數(shù)可以是包含多個(gè)標(biāo)頭的 Map<String, ?> 或 MultiValueMap<String, ?>、值集合<?> 或單個(gè)值。 |
@PathVariable | 添加一個(gè)變量,用于擴(kuò)展請(qǐng)求 URL 中的占位符。參數(shù)可以是包含多個(gè)變量的 Map<String, ?> 或單個(gè)值。 |
@RequestBody | 提供請(qǐng)求的正文,既可以是要序列化的對(duì)象,也可以是 Reactive Streams Publisher(如 Mono、Flux 或通過配置的 ReactiveAdapterRegistry 支持的任何其他異步類型)。 |
@RequestParam | 添加一個(gè)或多個(gè)請(qǐng)求參數(shù)。參數(shù)可以是包含多個(gè)參數(shù)的 Map<String, ?> 或 MultiValueMap<String, ?>、數(shù)值集合<?> 或單個(gè)數(shù)值。 當(dāng) "content-type"設(shè)置為 "application/x-www-form-urlencoded "時(shí),請(qǐng)求參數(shù)將在請(qǐng)求正文中編碼。否則,它們將作為 URL 查詢參數(shù)添加。 |
@RequestPart | 添加一個(gè)請(qǐng)求部分,它可以是字符串(表單字段)、資源(文件部分)、對(duì)象(要編碼的實(shí)體,如 JSON)、HttpEntity(部分內(nèi)容和標(biāo)頭)、Spring 部分或上述任何部分的 Reactive Streams 發(fā)布器。 |
@CookieValue | 添加一個(gè)或多個(gè) cookie。參數(shù)可以是包含多個(gè) cookie 的 Map<String, ?> 或 MultiValueMap<String, ?>、值集合<?> 或單個(gè)值。 |
支持的返回值
返回值 | 說明 |
| 執(zhí)行給定的請(qǐng)求,并發(fā)布響應(yīng)內(nèi)容(如果有)。 |
| 執(zhí)行給定的請(qǐng)求,釋放響應(yīng)內(nèi)容(如果有),并返回響應(yīng)標(biāo)頭。 |
| 執(zhí)行給定的請(qǐng)求,并根據(jù)聲明的返回類型對(duì)響應(yīng)內(nèi)容進(jìn)行解碼。 |
| 執(zhí)行給定的請(qǐng)求,并將響應(yīng)內(nèi)容解碼為已聲明元素類型的數(shù)據(jù)流。 |
| 執(zhí)行給定的請(qǐng)求,釋放響應(yīng)內(nèi)容(如果有),并返回一個(gè)包含狀態(tài)和標(biāo)頭的 ResponseEntity。 |
| 執(zhí)行給定的請(qǐng)求,按照聲明的返回類型解碼響應(yīng)內(nèi)容,并返回一個(gè)包含狀態(tài)、標(biāo)頭和解碼后正文的 ResponseEntity。 |
Mono<ResponseEntity<Flux<T>> | 執(zhí)行給定的請(qǐng)求,將響應(yīng)內(nèi)容解碼為已聲明元素類型的數(shù)據(jù)流,并返回一個(gè)包含狀態(tài)、標(biāo)頭和解碼后的響應(yīng)正文數(shù)據(jù)流的 ResponseEntity。 |
默認(rèn)情況下,WebClient為4xx和5xx HTTP狀態(tài)代碼引發(fā)WebClientResponseException。要自定義此項(xiàng),可以注冊(cè)響應(yīng)狀態(tài)處理程序,該處理程序應(yīng)用于通過客戶端執(zhí)行的所有響應(yīng):
WebClient client = WebClient.builder() // 狀態(tài)碼為4xx或5xx .defaultStatusHandler(HttpStatusCode::isError, resp -> Mono.just(new RuntimeException(resp.statusCode().toString() + "請(qǐng)求錯(cuò)誤"))) .baseUrl("http://localhost:8088/").build() ;HttpServiceProxyFactory factory = HttpServiceProxyFactory .builder(WebClientAdapter.forClient(client)).build() ;
該接口是在Spring6.1.1版本中才有的,是一個(gè)同步 HTTP 客戶端,提供現(xiàn)代、流暢的 API。
創(chuàng)建RestClientRestClient 是通過靜態(tài)創(chuàng)建方法之一創(chuàng)建的。你還可以使用 builder 獲取帶有更多選項(xiàng)的生成器,例如指定要使用的 HTTP 庫和要使用的消息轉(zhuǎn)換器,設(shè)置默認(rèn) URI、默認(rèn)路徑變量、默認(rèn)請(qǐng)求頭,或注冊(cè)攔截器和初始化器。
創(chuàng)建(或構(gòu)建)后,RestClient 可由多個(gè)線程安全使用。
// 默認(rèn)通過靜態(tài)方法創(chuàng)建RestClient restClient = RestClient.create();// 自定義方式RestClient restClient = RestClient.builder() .requestFactory(new HttpComponentsClientHttpRequestFactory()) // 自定義消息轉(zhuǎn)換器 // .messageConverters(converters -> converters.add(new PackCustomMessageConverter())) .baseUrl("http://localhost:8088") .defaultUriVariables(Map.of("id", "888")) .defaultHeader("x-api-token", "aabbcc") .requestInterceptor(new ClientHttpRequestInterceptor() { @Override public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { System.out.println("我是攔截器") ; return execution.execute(request, body) ; } }) .requestInitializer(new ClientHttpRequestInitializer() { @Override public void initialize(ClientHttpRequest request) { System.out.println("我是初始化器") ; request.getHeaders().add("x-version", "1.0.0") ; } }) .build() ;
調(diào)用及處理返回值
Users users = customClient.get() .uri("/demos/users/{id}") .retrieve() .body(Users.class) ;
post+body請(qǐng)求方式
Users user = new Users();ResponseEntity<Void> response = restClient.post() .uri("/demos/users") .contentType(APPLICATION_JSON) .body(user) .retrieve() .toBodilessEntity() ;
錯(cuò)誤處理默認(rèn)情況下,當(dāng)返回狀態(tài)代碼為 4xx 或 5xx 的響應(yīng)時(shí),RestClient 會(huì)拋出 RestClientException 的子類。可以使用 onStatus.RestClientException 命令重寫該行為。
Users users = customClient.get() .uri("/demos/users/{id}") .retrieve() // 處理返回狀態(tài)碼為:4xx和5xx .onStatus(HttpStatusCode::isError, (request, response) -> { throw new RuntimeException(response.getStatusCode().toString() + "請(qǐng)求錯(cuò)誤") ; }) .body(Users.class) ;
總結(jié):實(shí)現(xiàn)遠(yuǎn)程接口調(diào)用方面的強(qiáng)大功能。無論是使用WebClient、RestTemplate、HTTP Interface還是直接使用RestClient,Spring都提供了豐富的工具和接口來簡化開發(fā)者的操作。這些工具和接口不僅具有高性能、低內(nèi)存占用的優(yōu)點(diǎn),而且提供了良好的可擴(kuò)展性和靈活性,使得開發(fā)者可以根據(jù)實(shí)際需求進(jìn)行定制化開發(fā)。
本文鏈接:http://www.www897cc.com/showinfo-26-41686-0.htmlSpring6提供的四種遠(yuǎn)程接口調(diào)用神器!你知道那種?
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com