Spring REST med en Zuul Proxy

1. Oversigt

I denne artikel undersøger vi kommunikation mellem en front-end-applikation og en REST API, der implementeres separat.

Målet er at omgå CORS og samme oprindelsespolitiks begrænsning af browseren og give brugergrænsefladen mulighed for at ringe til API, selvom de ikke deler den samme oprindelse.

Vi opretter dybest set to separate applikationer - en UI-applikation og en simpel REST API, og vi bruger Zuul-fuldmægtigen i UI-applikationen til proxy-opkald til REST API.

Zuul er en JVM-baseret router og serversides belastningsbalancer fra Netflix. Og Spring Cloud har en god integration med en indlejret Zuul-proxy - hvilket er det, vi bruger her.

2. Maven-konfiguration

Først skal vi tilføje en afhængighed af zuul-understøttelsen fra Spring Cloud til vores UI-applikationer pom.xml:

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

Den seneste version kan findes her.

3. Zuul Properties

Dernæst - vi skal konfigurere Zuul, og da vi bruger Spring Boot, skal vi gøre det i ansøgning.yml:

zuul: ruter: foos: sti: / foos / ** url: // localhost: 8081 / spring-zuul-foos-resource / foos

Noter det:

  • Vi proxyer til vores ressource server Foos.
  • Alle anmodninger fra brugergrænsefladen, der starter med “/ foos /”Vil blive dirigeret til vores Foos Ressource server på // loclahost: 8081 / spring-zuul-foos-resource / foos /

4. API'en

Vores API-applikation er en simpel Spring Boot-app.

Inden for denne artikel vil vi overveje API'en, der er implementeret i en server, der kører på port 8081.

Lad os først definere den grundlæggende DTO for den ressource, vi skal bruge:

offentlig klasse Foo {privat lang id; privat strengnavn; // standard getters og setter}

Og en simpel controller:

@RestController public class FooController {@GetMapping ("/ foos / {id}") public Foo findById (@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {return new Foo (Long.parseLong (randomNumeric (2)), randomAlph 4)); }}

5. UI-applikationen

Vores UI-applikation er også en simpel Spring Boot-applikation.

Inden for denne artikel vil vi overveje API'en, der er implementeret i en server, der kører på port 8080.

Lad os starte med det vigtigste index.html - ved hjælp af lidt AngularJS:

     var app = angular.module ('myApp', ["ngResource"]); app.controller ('mainCtrl', funktion ($ scope, $ resource, $ http) {$ scope.foo = {id: 0, navn: "sample foo"}; $ scope.foos = $ resource ("/ foos / : fooId ", {fooId: '@ id'}); $ scope.getFoo = funktion () {$ scope.foo = $ scope.foos.get ({fooId: $ scope.foo.id});}}) ; {{foo.id}} {{foo.name}} Ny Foo 

Det vigtigste aspekt her er, hvordan vi får adgang til API'en ved hjælp af relative URL'er!

Husk, at API-applikationen ikke er implementeret på den samme server som UI-applikationen, så relative URL'er skal ikke fungere, og fungerer ikke uden proxyen.

Med proxyen får vi dog adgang til Foo ressourcer gennem Zuul-proxyen, som naturligvis er konfigureret til at dirigere disse anmodninger til hvor som helst API'et faktisk er implementeret.

Og endelig, den faktisk Boot-aktiverede applikation:

@EnableZuulProxy @ SpringBootApplication offentlig klasse UiApplication udvider SpringBootServletInitializer {public static void main (String [] args) {SpringApplication.run (UiApplication.class, args); }}

Ud over den enkle Boot-kommentar skal du bemærke, at vi også bruger aktiverings-stil af kommentar til Zuul-proxyen, som også er ret cool, ren og kortfattet.

6. Test routingen

Lad os nu teste vores UI-applikation som følger:

@Test offentlig ugyldig nårSendRequestToFooResource_thenOK () {Response response = RestAssured.get ("// localhost: 8080 / foos / 1"); assertEquals (200, respons.getStatusCode ()); }

7. Et brugerdefineret Zuul-filter

Der er flere Zuul-filtre tilgængelige, og vi kan også oprette vores egne brugerdefinerede:

@Komponent offentlig klasse CustomZuulFilter udvider ZuulFilter {@Override public Object run () {RequestContext ctx = RequestContext.getCurrentContext (); ctx.addZuulRequestHeader ("Test", "TestSample"); returnere null; } @ Override public boolean shouldFilter () {return true; } // ...}

Dette enkle filter tilføjer bare et overskrift kaldet “Prøve”Til anmodningen - men selvfølgelig kan vi blive så komplekse, som vi har brug for, her udvide vores anmodninger.

8. Test brugerdefineret Zuul-filter

Lad os endelig teste, om vores tilpassede filter fungerer - først vil vi ændre vores FooController på Foos ressource server:

@RestController public class FooController {@GetMapping ("/ foos / {id}") public Foo findById (@PathVariable long id, HttpServletRequest req, HttpServletResponse res) {if (req.getHeader ("Test")! = Null) {res .addHeader ("Test", req.getHeader ("Test")); } returner ny Foo (Long.parseLong (randomNumeric (2)), randomAlphabetic (4)); }}

Nu - lad os teste det:

@Test offentlig ugyldig nårSendRequest_thenHeaderAdded () {Response response = RestAssured.get ("// localhost: 8080 / foos / 1"); assertEquals (200, respons.getStatusCode ()); assertEquals ("TestSample", respons.getHeader ("Test")); }

9. Konklusion

I denne opskrivning fokuserede vi på at bruge Zuul til at dirigere anmodninger fra en UI-applikation til en REST API. Vi arbejdede med succes omkring CORS og samme oprindelsespolitik, og det lykkedes os også at tilpasse og udvide HTTP-anmodningen under transit.

Det fuld implementering af denne vejledning kan findes i GitHub-projektet - dette er et Maven-baseret projekt, så det skal være let at importere og køre som det er.