אביב 5 WebClient

1. סקירה כללית

במדריך זה, אנו הולכים לבחון את WebClient, שהוא לקוח אינטרנט תגובתי שהוצג באביב 5.

אנחנו גם הולכים להסתכל על WebTestClient, א WebClient תוכנן לשימוש בבדיקות.

2. מה זה WebClient?

פשוט שים, WebClient הוא ממשק המייצג את נקודת הכניסה העיקרית לביצוע בקשות אינטרנט.

הוא נוצר כחלק ממודול Spring Reactive, והוא יחליף את הקלאסיקה RestTemplate בתרחישים אלה. בנוסף, הלקוח החדש הוא פתרון תגובתי ולא חוסם שעובד על פרוטוקול HTTP / 1.1.

לבסוף, לממשק יש יישום יחיד, ה- DefaultWebClient בכיתה, שאיתה נעבוד.

3. תלות

מכיוון שאנו משתמשים ביישום Spring Boot, אנו זקוקים ל אביב-אתחול-התחלה-ווב-שטף תלות, כמו גם פרויקט הכור.

3.1. בניין עם מייבן

בואו נוסיף את התלות הבאות ל- pom.xml קוֹבֶץ:

 org.springframework.boot spring-boot-starter-webflux org.projectreactor reactor-spring 1.0.1.RELEASE 

3.2. בונה עם גרדל

עם Gradle, עלינו להוסיף את הערכים הבאים ל- build.gradle קוֹבֶץ:

תלות {compile 'org.springframework.boot: spring-boot-starter-webflux' compile 'org.projectreactor: reactor-spring: 1.0.1. RELEASE'}

4. עבודה עם WebClient

כדי לעבוד כמו שצריך עם הלקוח, עלינו לדעת כיצד:

  • ליצור מופע
  • הגיש בקשה
  • לטפל בתגובה

4.1. ליצור WebClient למשל

ישנן שלוש אפשרויות לבחירה. הראשון הוא יצירת WebClient אובייקט עם הגדרות ברירת מחדל:

WebClient client1 = WebClient.create (); 

האפשרות השנייה היא ליזום א WebClient מופע עם URI בסיס נתון:

WebClient client2 = WebClient.create ("// localhost: 8080"); 

האפשרות השלישית (והמתקדמת ביותר) היא בניית לקוח באמצעות DefaultWebClientBuilder בכיתה, המאפשר התאמה אישית מלאה:

WebClient client3 = WebClient .builder () .baseUrl ("// localhost: 8080") .defaultCookie ("cookieKey", "cookieValue") .defaultHeader (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUEValueVarue) .default. "," // localhost: 8080 ")) .build ();

4.2. ליצור WebClient מופע עם פסק זמן

לעתים קרובות, פסק זמן ה- HTTP המוגדר כברירת מחדל של 30 שניות איטי מדי לצרכים שלנו, אז בואו נראה כיצד להגדיר אותם עבורנו WebClient למשל.

מעמד הליבה בו אנו משתמשים הוא TcpClient.

שם אנחנו יכולים הגדר את פסק הזמן לחיבור דרך ChannelOption.CONNECT_TIMEOUT_MILLIS ערך. אנחנו יכולים גם הגדירו את פסק הזמן לקריאה וכתיבה באמצעות ReadTimeoutHandler ו WriteTimeoutHandler, בהתאמה:

TcpClient tcpClient = TcpClient .create () .option (ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .doOnConnected (חיבור -> {connection.addHandlerLast (ReadTimeoutHandler חדש (5000, TimeUnit.MILLISECONDS)); חיבור.אדנדלר. מיליוני שניות));}); לקוח WebClient = WebClient.builder () .clientConnector (ReactorClientHttpConnector חדש (HttpClient.from (tcpClient))) .build ();

ציין זאת בזמן שאנחנו יכולים להתקשר פסק זמן גם על פי בקשת הלקוח שלנו, מדובר בפסק זמן של אות, לא בחיבור HTTP, או בפסק זמן של קריאה / כתיבה; זה פסק זמן עבור המו"ל Mono / Flux.

4.3. הכנת בקשה

ראשית עלינו לציין שיטת HTTP של בקשה על ידי הפעלת שיטה (שיטת HttpMethod) או לקרוא לשיטות הקיצור שלו כמו לקבל, הודעה, ו לִמְחוֹק:

WebClient.UriSpec request1 = client3.method (HttpMethod.POST); WebClient.UriSpec request2 = client3.post ();

השלב הבא הוא לספק כתובת אתר. אנחנו יכולים להעביר את זה ל אורי API כ- חוּט או א java.net.URL למשל:

WebClient.RequestBodySpec uri1 = client3 .method (HttpMethod.POST) .uri ("/ resource"); WebClient.RequestBodySpec uri2 = client3 .post () .uri (URI.create ("/ resource"));

אז נוכל להגדיר גוף בקשה, סוג תוכן, אורך, קובצי cookie או כותרות אם נצטרך.

לדוגמא, אם אנו רוצים להגדיר גוף בקשה, ישנן שתי דרכים זמינות: מילויו ב- BodyInserter או האצלת עבודה זו ל- מוֹצִיא לָאוֹר:

WebClient.RequestHeadersSpec requestSpec1 = WebClient .create () .method (HttpMethod.POST) .uri ("/ resource") .body (BodyInserters.fromPublisher (Mono.just ("data")), String.class); WebClient.RequestHeadersSpec requestSpec2 = WebClient .create ("// localhost: 8080") .post () .uri (URI.create ("/ resource")) .body (BodyInserters.fromObject ("data"));

ה BodyInserter הוא ממשק האחראי על אכלוס a תגובתי HttpOutputMessage גוף עם הודעת פלט נתונה והקשר המשמש במהלך ההכנסה. א מוֹצִיא לָאוֹר הוא רכיב תגובתי שאחראי על מתן מספר בלתי אפשרי של אלמנטים ברצף.

הדרך השנייה היא גוּף שיטה, שהיא קיצור דרך למקור גוף (מוסיף BodyInserter) שיטה.

כדי להקל על תהליך מילוי א BodyInserter, יש מבני גוף בכיתה עם מספר שיטות שימושיות לשימוש:

BodyInserter inserter1 = BodyInserters .fromPublisher (מנוי :: onComplete, String.class); 

אפשר גם עם MultiValueMap:

LinkedMultiValueMap map = חדש LinkedMultiValueMap (); map.add ("key1", "value1"); map.add ("key2", "value2"); BodyInserter inserter2 = BodyInserters.fromMultipartData (מפה); 

או באמצעות אובייקט יחיד:

BodyInserter inserter3 = BodyInserters.fromObject (אובייקט חדש ()); 

אחרי שהגדרנו את הגוף, נוכל להגדיר כותרות, עוגיות וסוגי מדיה מקובלים. ערכים יתווספו לאלו שכבר נקבעו בעת הפעלת הלקוח.

כמו כן, יש תמיכה נוספת לכותרות הנפוצות ביותר כמו "אם אין התאמה", "אם שונה מאז", "קבל", ו "קבל-צ'ארסט".

הנה דוגמה כיצד ניתן להשתמש בערכים אלה:

WebClient.ResponseSpec response1 = uri1 .body (inserter3) .header (HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE). Accept (MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML) .acceptCharset (Charset (Charset) (". "*") .ifModifiedSince (ZonedDateTime.now ()). retrieve ();

4.4. קבלת תגובה

השלב האחרון הוא שליחת הבקשה וקבלת תגובה. ניתן לעשות זאת באמצעות ה- לְהַחלִיף או ה להחזיר שיטה.

שיטות אלה נבדלות בסוגי ההחזר; ה לְהַחלִיף השיטה מספקת א ClientResponse יחד עם מעמדו וכותרותיו, ואילו להחזיר השיטה היא הדרך הקצרה ביותר להביא גוף באופן ישיר:

מחרוזת תגובה2 = בקשה1.חלפה () .בלוק () .bodyToMono (מחרוזת.קלאס) .בלוק (); מחרוזת תגובה 3 = בקשה 2 .חזור (). BodyToMono (מחרוזת.קלאס) .בלוק ();

חשוב לשים לב ל bodyToMono שיטה, שתזרוק א WebClientException אם קוד המצב הוא 4xx (שגיאת לקוח) או 5xx (שגיאת שרת). אנו משתמשים ב- לַחסוֹם שיטה ב מונוs כדי להירשם ולאחזר נתונים בפועל שנשלחו עם התגובה.

5. עבודה עם WebTestClient

ה WebTestClient היא נקודת הכניסה העיקרית לבדיקת נקודות קצה של שרת WebFlux. יש לו ממשק API דומה מאוד ל- WebClient, והיא מאצילה את מרבית העבודה לפנימי WebClient מופע המתמקד בעיקר במתן הקשר מבחן. ה DefaultWebTestClient class הוא יישום ממשק יחיד.

הלקוח לבדיקה יכול להיות קשור לשרת אמיתי או לעבוד עם בקרים או פונקציות ספציפיים.

5.1. כריכה לשרת

כדי להשלים בדיקות אינטגרציה מקצה לקצה עם בקשות בפועל לשרת פועל, אנו יכולים להשתמש ב- bindToServer שיטה:

WebTestClient testClient = WebTestClient .bindToServer () .baseUrl ("// localhost: 8080") .build (); 

5.2. כריכה לנתב

אנחנו יכולים לבדוק מסוים RouterFunction על ידי העברתו ל bindToRouterFunction שיטה:

פונקציית RouterFunction = RouterFunctions.route (RequestPredicates.GET ("/ resource"), בקשה -> ServerResponse.ok (). Build ()); WebTestClient .bindToRouterFunction (פונקציה) .build (). Get (). Uri ("/ resource"). Exchange () .expectStatus (). IsOk () .expectBody (). IsEmpty (); 

5.3. כריכה למטפל באינטרנט

אותה התנהגות ניתן להשיג עם ה- bindToWebHandler שיטה, שלוקחת א WebHandler למשל:

מטפל ב- WebHandler = exchange -> Mono.empty (); WebTestClient.bindToWebHandler (מטפל) .build ();

5.4. כריכה להקשר יישום

מצב מעניין יותר מתרחש כאשר אנו משתמשים ב- bindToApplicationContext שיטה. זה לוקח ApplicationContext ומנתח את ההקשר לשעועית בקר ו @EnableWebFlux תצורות.

אם אנו מזריקים מופע של ApplicationContext, קטע קוד פשוט עשוי להיראות כך:

@Autowired פרטי ApplicationContext הקשר; WebTestClient testClient = WebTestClient.bindToApplicationContext (context) .build (); 

5.5. כריכה לבקר

גישה קצרה יותר היא לספק מגוון בקרים שאנו רוצים לבדוק על ידי bindToController שיטה. בהנחה שיש לנו בקר בכיתה והזרקנו אותה לשיעור הדרוש, נוכל לכתוב:

@ בקר בקר פרטי אוטומטי; WebTestClient testClient = WebTestClient.bindToController (בקר) .build (); 

5.6. להגיש בקשה

לאחר בניית א WebTestClient אובייקט, כל הפעולות הבאות בשרשרת יהיו דומות ל WebClient עד ה לְהַחלִיף שיטה (אחת הדרכים לקבל תגובה), המספקת את WebTestClient.ResponseSpec ממשק לעבודה עם שיטות שימושיות כמו expectStatus, expectBody, ו expectHeader:

WebTestClient .bindToServer () .baseUrl ("// localhost: 8080") .build () .post () .uri ("/ resource"). Exchange () .expectStatus (). IsCreated () .expectHeader (). ValueEquals ("סוג תוכן", "application / json") .expectBody (). IsEmpty (); 

6. מסקנה

במאמר זה בחנו את WebClient, מנגנון אביב משופר חדש לביצוע בקשות בצד הלקוח.

בדקנו גם את היתרונות שהוא מציע בכך שעברנו את תצורת הלקוח, הכנת הבקשה ועיבוד התגובה.

כל קטעי הקוד המוזכרים במאמר נמצאים במאגר GitHub שלנו.