精講響應式WebClient第2篇-GET請求阻塞與非阻塞呼叫方法詳解

字母哥部落格發表於2020-08-21

本文是精講響應式WebClient第2篇,前篇的blog訪問地址如下:

在上一篇文章為大家介紹了響應式IO模型和WebClient的基本用法。本節來繼續深入的為大家介紹:如何使用WebClient作為Http客戶端傳送GET請求與進行響應結果的接收。

一、block()阻塞式獲取響應結果

WebClient客戶端既支援同步非同步、阻塞與非阻塞IO,我們先來為大家介紹一下同步阻塞式的程式設計方式。即:在請求傳送之後使用block()方法,阻塞當前執行緒等待獲取響應結果。

1.1.使用Mono接收單個物件

建立測試用例,成員變數WebClient,以 "http://jsonplaceholder.typicode.com" 為訪問服務基礎路徑,該網站是一個免費提供RESTful API進行介面測試的一個網站。

public class GetTest {

  //建立webClient
  private WebClient webClient = WebClient.builder()
          .baseUrl("http://jsonplaceholder.typicode.com")
          .build();


  @Test
  public void testMono() {
    Mono<PostDTO> mono = webClient
            .get()    // 傳送GET 請求
            .uri("/posts/1")  //服務請求路徑,基於baseurl
            .retrieve() // 獲取響應體
            .bodyToMono(PostDTO.class); //響應資料型別轉換
    System.out.println(mono.block());
  }

}
  • get() 方法表示使用HTTP GET method
  • uri() 指定服務介面路徑,以baseurl為基礎
  • retrieve() 獲取響應體,即HTTP body
  • bodyToMono()將響應體轉換為一個物件,Mono英文是單聲道、單體的意思,用於接收單個物件

通過瀏覽器訪問 "http://jsonplaceholder.typicode.com/posts/1" 得到JSON響應結果,和我們通過程式列印出的響應結果資料內容一致。程式控制臺截圖如下:

接收響應結果的java POJO實體物件如下:

import lombok.Data;

@Data
public class PostDTO {
    private int userId;
    private int id;
    private String title;
    private String body;
}

1.2.使用Flux接收集合物件

訪問http://jsonplaceholder.typicode.com/posts 可以獲得JSON陣列方式的請求結果如圖(一共100條我截圖擷取3條記錄):


所以我們需要通過bodyToFlux方法將請求結果轉為Flux<PostDTO>,通過flux.collectList().block();接收響應資料為 List<PostDTO>集合。Flux英文含義:流動的,用於接收集合元素響應結果。

@Test
public void testFlux() {
  Flux<PostDTO> flux = webClient
          .get() // 傳送GET 請求
          .uri("/posts")  //服務請求路徑,基於baseurl
          .retrieve() // 獲取響應體
          .bodyToFlux(PostDTO.class); //響應資料型別轉換
  List<PostDTO> posts = flux.collectList().block();
  assert posts != null;
  System.out.println("獲取posts集合元素數量:" + posts.size());
}

控制檯列印結果如下:

二、subscribe()非阻塞式獲取響應結果

與block()阻塞式獲取響應結果不同,使用subscribe()非同步訂閱響應結果,不會阻塞主執行緒繼續向下執行。獲取到響應結果之後,由回撥函式handleResponse處理響應結果。

@Test
public void testSubscribe() throws InterruptedException {
  Mono<PostDTO> mono = webClient
          .get()    // 傳送GET 請求
          .uri("/posts/1")  //服務請求路徑,基於baseurl
          .retrieve() // 獲取響應體
          .bodyToMono(PostDTO.class); //響應資料型別轉換

  //非同步非阻塞處理響應結果
  mono.subscribe(GetTest::handleResponse);
  //為了避免測試用例主執行緒執行完成,導致看不到非同步處理結果
  Thread.currentThread().sleep(10000);
}

//響應結果處理回撥方法
private static void handleResponse(PostDTO postDTO) {
  System.out.println("handle response:=======================");
  System.out.println(postDTO);
}

控制檯列印輸出結果如下:

三、exchange()獲取HTTP響應完整內容

上文中retrieve()只能獲取HTTP報文中的Body,也就是響應體。如果我們想獲取HTTP報文中的狀態碼、headers、cookies等資訊,需要使用exchange()方法。

@Test
public void testExchange() {
  Mono<ClientResponse> mono = webClient
          .get()    // 傳送GET 請求
          .uri("/posts/1")  //服務請求路徑,基於baseurl
          .exchange();

  System.out.println(mono.block());


  // 獲取完整的響應物件
  ClientResponse response = mono.block();

  assert response != null;
  HttpStatus httpStatus = response.statusCode(); // 獲取響應狀態
  int statusCodeValue = response.rawStatusCode(); // 獲取響應狀態碼
  ClientResponse.Headers headers = response.headers(); // 獲取響應頭

  // 獲取響應體
  Mono<PostDTO> resultMono = response.bodyToMono(PostDTO.class);
  PostDTO postDTO = resultMono.block();

  // 輸出結果
  System.out.println("響應狀態:" + httpStatus);
  System.out.println("響應狀態碼值:" + statusCodeValue);
  System.out.println("HTTP Headers:" + headers.asHttpHeaders());
  System.out.println("響應體:" + postDTO);
}

HTTP報文資訊詳情控制檯列印結果

四、佔位符傳參

非佔位符傳參,寫死的引數方式不靈活

.uri("/posts/1")  //服務請求路徑,基於baseurl

第一種佔位符傳參:數字順序佔位符

Mono<String> mono = webClient.uri("/{1}/{2}", "posts", "1") 

第二種佔位符傳參:引數名稱佔位符

String type = "posts";
int id = 1;
 
Mono<String> mono = webClient.uri("/{type}/{id}", type, id)  

第三種通過map傳參

Map<String,Object> map = new HashMap<>();
map.put("type", "posts");
map.put("id", 1);
 
Mono<String> mono = webClient
.uri("/{type}/{id}", map) 

歡迎關注我的部落格,裡面有很多精品合集

  • 本文轉載註明出處(必須帶連線,不能只轉文字):字母哥部落格

覺得對您有幫助的話,幫我點贊、分享!您的支援是我不竭的創作動力! 。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

相關文章