有了WebClient還在用RestTemplate?

WebClient

Spring5

引入的,基於響應式程式設計實現的

HTTP

呼叫客戶端。

Spring

官方推薦使用

WebClient

替代

RestTemplate

完成

HTTP

呼叫。因為

WebClient

是基於

Reactor

實現的,所以既可以支援阻塞呼叫也可以支援非阻塞呼叫,在高併發的場景下資源利用率更高。這也是官方推薦使用的重要原因之一。

如果大家不瞭解響應式程式設計,強烈建議可以先看一下我這篇文章,這樣對本篇文章中的樣例程式碼也會有些幫助。

如果在工程中想要使用

WebClient

,在

Pom

檔案中加入如下依賴

org。springframework。boot spring-boot-starter-webflux

如果使用的是

Gradle

,則加入如下依賴

dependencies { compile ‘org。springframework。boot:spring-boot-starter-webflux’ }

初始化WebClient

直接初始化,不加任何引數。

WebClient client = WebClient。create();

初始化時,提供一個預設的呼叫地址。

WebClient client = WebClient。create(“http://localhost:8080”);

自定義引數初始化。

WebClient client = WebClient。builder() 。baseUrl(“http://localhost:8080”) 。defaultCookie(“cookieKey”, “cookieValue”) 。defaultHeader(HttpHeaders。CONTENT_TYPE, MediaType。APPLICATION_JSON_VALUE) 。defaultUriVariables(Collections。singletonMap(“url”, “http://localhost:8080”)) 。build();

修改預設的超時時間。

//透過HttpClient設定超時時間HttpClient httpClient = HttpClient。create() //設定連線超時時間 。option(ChannelOption。CONNECT_TIMEOUT_MILLIS, 5000) //設定響應超時時間 。responseTimeout(Duration。ofMillis(5000)) //分別設定讀寫超時時間 。doOnConnected(conn -> conn。addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit。MILLISECONDS)) 。addHandlerLast(new WriteTimeoutHandler(5000,TimeUnit。MILLISECONDS))); WebClient client = WebClient。builder()。clientConnector(new ReactorClientHttpConnector(httpClient))。build();

發起Get請求

以阻塞的方式獲取0或者1個返回結果,用

Mono

表示

//透過builder的方式初始化WebClientWebClient webClient = WebClient。builder() //配置頭部資訊 。defaultHeader(HttpHeaders。ACCEPT_CHARSET, “UTF-8”)//定義過濾器 。filter(ExchangeFilterFunctions。basicAuthentication(“user”,“password”))。filter((clientRequest, next) -> { logger。info(“Request: {} {}”,clientRequest。method(),clientRequest。url());clientRequest。headers() 。forEach((name, values) -> values。forEach(value -> logger。info(“{}={}”, name, value)));return next。exchange(clientRequest);})。build();//發起GET請求Mono resp = webClient。get()。uri(“https://localhost:8080”) //獲取結果 。retrieve()//將結果轉化為指定型別 。bodyToMono(String。class);//以阻塞的方式將結果打印出來logger。info(“result:{}”,resp。block());

以阻塞方式獲取多個返回結果,用

Flux

表示

Flux bookFlux = WebClient。create() 。method(HttpMethod。GET) 。uri(“http://localhost:8080/books”) 。retrieve() 。bodyToFlux(Book。class); //透過阻塞的方式獲取響應結果 List books = bookFlux。collectList()。block(); //透過非阻塞的方式獲取響應結果 bookFlux。subscribe(book ->{System。out。print(book。getName());});

透過非阻塞方式獲取響應結果

Flux bookFlux = WebClient。create() 。method(HttpMethod。GET) 。uri(“http://localhost:8080/books”) 。retrieve() 。bodyToFlux(Book。class); //透過非阻塞的方式獲取響應結果 bookFlux。subscribe(book ->{System。out。print(book。getName());});

透過佔位符傳參

Mono mono = WebClient。create() 。method(HttpMethod。POST) 。uri(“http://localhost:8080/book/{id}/{name}”, “1”, “java”) 。retrieve() 。bodyToMono(String。class); String result = mono。block();

除了佔位符傳參,還可以透過map形式傳參等等,這裡不一一舉例介紹了。

發起POST請求

發起

POST

請求,提交

Form

表單

MultiValueMap formData = new LinkedMultiValueMap<>();formData。add(“name1”,“value1”);formData。add(“name2”,“value2”);Mono resp = WebClient。create()。post() 。uri(“http://localhost:8080/submit”) 。contentType(MediaType。APPLICATION_FORM_URLENCODED) 。body(BodyInserters。fromFormData(formData)) 。retrieve()。bodyToMono(String。class); logger。info(“result:{}”,resp。block());

使用

Raw Json

的方式發起

POST

請求。

Mono resp = WebClient。create()。post() 。uri(“http://localhost:8080/book/json”) 。contentType(MediaType。APPLICATION_JSON) 。body(BodyInserters。fromValue(“{\n” + “ \”name\“ : \”java\“,\n” + “ \”price\“ : \”32。5\“ \n” + “ }”)) 。retrieve()。bodyToMono(String。class);logger。info(“result:{}”,resp。block());

錯誤和異常處理

WebClient可以更優雅地處理錯誤和異常。

//建立WebClient WebClient webClient = WebClient。builder() 。baseUrl(“http://localhost:8080”) 。defaultHeader(HttpHeaders。CONTENT_TYPE, “application/json”) 。defaultHeader(HttpHeaders。ACCEPT_CHARSET, “UTF-8”) 。build(); //發起Get請求 WebClient。ResponseSpec responseSpec = webClient。method(HttpMethod。GET) 。uri(“/book/remark/{id}”, “1”) 。retrieve(); //根據狀態碼進行響應 Mono mono = responseSpec 。onStatus(e -> e。is4xxClientError(),resp -> { logger。error(“error:{},msg:{}”,resp。statusCode()。value(),resp。statusCode()。getReasonPhrase()); return Mono。error(new RuntimeException(resp。statusCode()。value() + “ : ” + resp。statusCode()。getReasonPhrase())); }) 。bodyToMono(String。class) 。doOnError(WebClientResponseException。class, err -> { logger。info(“ERROR status:{},msg:{}”,err。getRawStatusCode(),err。getResponseBodyAsString()); throw new RuntimeException(err。getMessage()); }) 。onErrorReturn(“fallback”); String result = mono。block(); logger。info(“result:{}”,result);

總結

以上是一些

WebClient

使用的小

Demo

,希望對那些想了解

WebClient

的同學有一些幫助。如果想深入瞭解,建議還是多看看官方文件。