Spring REST med en Zuul Proxy

1. Oversikt

I denne artikkelen vil vi utforske kommunikasjon mellom et front-end-program og et REST API som distribueres separat.

Målet er å omgå CORS og samme opprinnelsesbegrensning i nettleseren og la brukergrensesnittet ringe API-et, selv om de ikke har samme opprinnelse.

Vi oppretter i utgangspunktet to separate applikasjoner - et brukergrensesnittapplikasjon og et enkelt REST API, og vi bruker det Zuul-fullmakten i UI-applikasjonen for å proxy-anrop til REST API.

Zuul er en JVM-basert ruter og serversides belastningsfordeler av Netflix. Og Spring Cloud har en fin integrasjon med en innebygd Zuul-proxy - det er det vi bruker her.

2. Maven-konfigurasjon

Først må vi legge til en avhengighet av zuul-støtten fra Spring Cloud til brukergrensesnittapplikasjonene våre pom.xml:

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

Den siste versjonen finner du her.

3. Zuul Properties

Neste - vi trenger å konfigurere Zuul, og siden vi bruker Spring Boot, skal vi gjøre det i application.yml:

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

Noter det:

  • Vi proxyer til ressursserveren vår Foos.
  • Alle forespørsler fra brukergrensesnittet som starter med “/ foos /”Vil bli dirigert til vår Foos Ressursserver kl // loclahost: 8081 / spring-zuul-foos-resource / foos /

4. API

API-applikasjonen vår er en enkel Spring Boot-app.

I denne artikkelen skal vi vurdere API-en distribuert i en server som kjører på port 8081.

La oss først definere den grunnleggende DTO for ressursen vi skal bruke:

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

Og en enkel kontroller:

@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-applikasjonen

UI-applikasjonen vår er også en enkel Spring Boot-applikasjon.

Innen denne artikkelen skal vi vurdere API-en distribuert i en server som kjører på port 8080.

La oss starte med det viktigste index.html - bruker litt AngularJS:

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

Det viktigste aspektet her er hvordan vi får tilgang til API bruker relative URL-er!

Husk at API-applikasjonen ikke er distribuert på samme server som UI-applikasjonen, så relative URL-er skal ikke fungere, og fungerer ikke uten proxyen.

Med proxyen får vi imidlertid tilgang til Foo ressurser gjennom Zuul-proxyen, som selvfølgelig er konfigurert til å dirigere disse forespørslene til hvor API-en faktisk er distribuert.

Og til slutt, den faktisk Boot-aktiverte applikasjonen:

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

Utover den enkle Boot-merknaden, legg merke til at vi bruker den aktiverende stilen til merknader for Zuul-proxyen, som også er ganske kul, ren og kortfattet.

6. Test rutingen

Nå - la oss teste UI-applikasjonen vår - som følger:

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

7. Et tilpasset Zuul-filter

Det er flere Zuul-filtre tilgjengelig, og vi kan også lage vår egen tilpassede:

@Component public class CustomZuulFilter utvider ZuulFilter {@Override public Object run () {RequestContext ctx = RequestContext.getCurrentContext (); ctx.addZuulRequestHeader ("Test", "TestSample"); return null; } @ Override public boolean shouldFilter () {return true; } // ...}

Dette enkle filteret legger bare til en overskrift som heter “Test”Til forespørselen - men selvfølgelig kan vi bli så kompliserte som vi trenger for å utvide våre forespørsler.

8. Test tilpasset Zuul-filter

Til slutt, la oss teste at vårt tilpassede filter fungerer - først endrer vi vårt FooController på Foos ressursserver:

@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)); }}

Nå - la oss teste det ut:

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

9. Konklusjon

I denne oppskriften fokuserte vi på å bruke Zuul til å rute forespørsler fra et UI-program til et REST API. Vi jobbet vellykket rundt CORS og policyen med samme opprinnelse, og vi klarte også å tilpasse og utvide HTTP-forespørselen under transport.

De full gjennomføring av denne opplæringen finnes i GitHub-prosjektet - dette er et Maven-basert prosjekt, så det skal være enkelt å importere og kjøre som det er.