אביב REST עם פרוקסי Zuul

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

במאמר זה נחקור את תקשורת בין יישום חזיתי ל- REST API הנפרשים בנפרד.

המטרה היא לעקוף את CORS ואת אותה הגבלת מדיניות מקור של הדפדפן ולאפשר לממשק המשתמש להתקשר ל- API למרות שהם לא חולקים את אותו המקור.

ניצור בעצם שתי יישומים נפרדים - יישום ממשק משתמש ו- API פשוט של REST, ונשתמש בו מיופה הכוח של זול ביישום UI לשיחות פרוקסי ל- API של REST.

Zuul הוא נתב מבוסס JVM ומאזן עומסי צד בשרת של Netflix. ולאביב ענן אינטגרציה נחמדה עם פרוקסי משובץ של Zuul - וזה מה שנשתמש כאן.

2. תצורת Maven

ראשית, עלינו להוסיף תלות בתמיכת zuul מ- Spring Cloud ליישומי ממשק המשתמש שלנו pom.xml:

 org.springframework.cloud spring-cloud-starter-netflix-zuul 2.2.0.RELEASE 

הגרסה האחרונה תוכל למצוא כאן.

3. נכסי צול

לאחר מכן - עלינו להגדיר את תצורת Zuul, ומכיוון שאנו משתמשים באביב אתחול, אנו נעשה זאת ב application.yml:

צוול: מסלולים: foos: path: / foos / ** url: // localhost: 8081 / spring-zuul-foos-resource / foos

ציין זאת:

  • אנו מתייחסים לשרת המשאבים שלנו פוס.
  • כל הבקשות מממשק המשתמש שמתחילות עם "/ foos /"ינותב לשלנו פוס שרת משאבים בכתובת // loclahost: 8081 / spring-zuul-foos-resource / foos /

4. ממשק ה- API

יישום ה- API שלנו הוא אפליקציית Spring Boot פשוטה.

במסגרת מאמר זה, נשקול את ה- API הפרוס בשרת הפועל בנמל 8081.

בואו נגדיר תחילה את ה- DTO הבסיסי עבור המשאב שאנו נשתמש בו:

מחלקה ציבורית Foo {מזהה פרטי ארוך; שם מחרוזת פרטי; // סטרים וקובעים סטנדרטיים}

ובקר פשוט:

@RestController מחלקה ציבורית FooController {@GetMapping ("/ foos / {id}") ציבור Foo findById (@PathVariable מזהה ארוך, HttpServletRequest req, HttpServletResponse res) {להחזיר Foo חדש (Long.parseLong (randomNumeric (2)), randomAlphab 4)); }}

5. יישום ממשק המשתמש

יישום ממשק המשתמש שלנו הוא גם יישום Spring Boot פשוט.

במסגרת מאמר זה, נשקול את ה- API הפרוס בשרת הפועל בנמל 8080.

נתחיל עם העיקרי index.html - באמצעות קצת AngularJS:

     var app = angular.module ('myApp', ["ngResource"]); app.controller ('mainCtrl', פונקציה ($ scope, $ resource, $ http) {$ scope.foo = {id: 0, name: "sample foo"}; $ scope.foos = $ resource ("/ foos / : fooId ", {fooId: '@ id'}); $ scope.getFoo = פונקציה () {$ scope.foo = $ scope.foos.get ({fooId: $ scope.foo.id});}}) ; {{foo.id}} {{foo.name}} Foo חדש 

ההיבט החשוב ביותר כאן הוא האופן שבו אנו ניגשים ל- API באמצעות כתובות אתרים יחסית!

זכור כי יישום ה- API אינו פרוס על אותו שרת כמו יישום ממשק המשתמש, כך שכתובות אתרים יחסית לא אמורות לעבוד, ולא יעבוד ללא ה- proxy.

עם ה- proxy, לעומת זאת, אנו ניגשים ל- פו משאבים דרך ה- Proxy של Zuul, שמוגדר כמובן לנתב את הבקשות הללו לכל מקום שבו ממש ה- API נפרס.

ולבסוף, היישום המאפשר למעשה אתחול:

@EnableZuulProxy @ SpringBootApplication מחלקה ציבורית UiApplication מרחיב את SpringBootServletInitializer {main public public static (String [] args) {SpringApplication.run (UiApplication.class, args); }}

מעבר לביאור האתחול הפשוט, שים לב שאנחנו משתמשים בסגנון ההפעלה של הערה גם עבור ה- proxy של Zuul, שהוא די מגניב, נקי ותמציתי.

6. בדוק את הניתוב

עכשיו - בואו נבדוק את יישום ממשק המשתמש שלנו - באופן הבא:

@Test הציבור בטל כאשרSendRequestToFooResource_thenOK () {תגובה תגובה = RestAssured.get ("// localhost: 8080 / foos / 1"); assertEquals (200, response.getStatusCode ()); }

7. מסנן זול מותאם אישית

ישנם מספר מסנני Zuul זמינים, ואנחנו יכולים גם ליצור אחד מותאם אישית משלנו:

המחלקה הציבורית @Component CustomZuulFilter מרחיב את ZuulFilter {@Override Object Object run () {RequestContext ctx = RequestContext.getCurrentContext (); ctx.addZuulRequestHeader ("Test", "TestSample"); החזר אפס; } @ Override בוליאני ציבורי shouldFilter () {להחזיר נכון; } // ...}

המסנן הפשוט הזה פשוט מוסיף כותרת בשם "מִבְחָןלבקשה - אך כמובן שנוכל להיות מורכבים ככל שאנו צריכים להגדיל את בקשותינו.

8. בדוק את מסנן הזול המותאם אישית

לבסוף, בואו נוודא שהמסנן המותאם אישית שלנו עובד - ראשית נשנה את שלנו FooController בשרת המשאבים Foos:

@RestController מחלקה ציבורית FooController {@GetMapping ("/ foos / {id}") ציבור Foo findById (@PathVariable מזהה ארוך, HttpServletRequest req, HttpServletResponse res) {if (req.getHeader ("Test")! = Null) {res .addHeader ("מבחן", req.getHeader ("מבחן")); } להחזיר Foo חדש (Long.parseLong (randomNumeric (2)), randomAlphabetic (4)); }}

עכשיו - בואו נבדוק את זה:

@ מבחן ציבורי בטל כאשר SendRequest_thenHeaderAdded () {תגובה תגובה = RestAssured.get ("// localhost: 8080 / foos / 1"); assertEquals (200, response.getStatusCode ()); assertEquals ("TestSample", response.getHeader ("Test")); }

9. מסקנה

במחקר זה התמקדנו בשימוש בזול לניתוב בקשות מיישום ממשק משתמש ל- API של REST. עבדנו בהצלחה סביב CORS ומדיניות אותה מקור והצלחנו להתאים אישית ולהגדיל את בקשת ה- HTTP במעבר.

ה יישום מלא של מדריך זה ניתן למצוא בפרויקט GitHub - זהו פרויקט מבוסס Maven, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.