RIPOSO di primavera con un proxy Zuul

1. Panoramica

In questo articolo, esploreremo la comunicazione tra un'applicazione front-end e un'API REST che vengono distribuite separatamente .

L'obiettivo è aggirare CORS e la restrizione dei criteri della stessa origine del browser e consentire all'interfaccia utente di chiamare l'API anche se non condividono la stessa origine.

Fondamentalmente creeremo due applicazioni separate: un'applicazione UI e una semplice API REST, e useremo il proxy Zuul nell'applicazione UI per proxy chiamate all'API REST.

Zuul è un router basato su JVM e un bilanciatore del carico lato server di Netflix. E Spring Cloud ha una bella integrazione con un proxy Zuul incorporato, che è quello che useremo qui.

2. Configurazione Maven

Innanzitutto, dobbiamo aggiungere una dipendenza al supporto zuul da Spring Cloud al pom.xml della nostra applicazione dell'interfaccia utente :

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

L'ultima versione può essere trovata qui.

3. Proprietà Zuul

Successivamente, dobbiamo configurare Zuul, e poiché stiamo usando Spring Boot, lo faremo in application.yml :

zuul: routes: foos: path: /foos/** url: //localhost:8081/spring-zuul-foos-resource/foos

Nota che:

  • Stiamo inviando un proxy al nostro server di risorse Foos.
  • Tutte le richieste dall'interfaccia utente che inizia con " / foos / " verranno indirizzate al nostro server di risorse Foos all'indirizzo // loclahost: 8081 / spring-zuul-foos-resource / foos /

4. L'API

La nostra applicazione API è una semplice app Spring Boot.

In questo articolo, prenderemo in considerazione l'API distribuita in un server in esecuzione sulla porta 8081.

Definiamo prima il DTO di base per la risorsa che utilizzeremo:

public class Foo { private long id; private String name; // standard getters and setters }

E un semplice 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)), randomAlphabetic(4)); } }

5. L'applicazione UI

La nostra applicazione UI è anche una semplice applicazione Spring Boot.

In questo articolo, prenderemo in considerazione l'API distribuita in un server in esecuzione sulla porta 8080.

Cominciamo con il principale index.html - usando un po 'di AngularJS:

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

L'aspetto più importante qui è come accediamo all'API utilizzando gli URL relativi!

Tieni presente che l'applicazione API non è distribuita sullo stesso server dell'applicazione UI, quindi gli URL relativi non dovrebbero funzionare e non funzioneranno senza il proxy.

Con il proxy, tuttavia, accediamo alle risorse Foo tramite il proxy Zuul, che è ovviamente configurato per instradare queste richieste ovunque l'API sia effettivamente distribuita.

E infine, l'applicazione effettivamente abilitata per l'avvio:

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

Oltre alla semplice annotazione di avvio, si noti che stiamo utilizzando lo stile di annotazione di abilitazione anche per il proxy Zuul, che è piuttosto interessante, pulito e conciso.

6. Testare il percorso

Ora - testiamo la nostra applicazione dell'interfaccia utente - come segue:

@Test public void whenSendRequestToFooResource_thenOK() { Response response = RestAssured.get("//localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); }

7. Un filtro Zuul personalizzato

Sono disponibili più filtri Zuul e possiamo anche crearne uno personalizzato:

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

Questo semplice filtro aggiunge semplicemente un'intestazione chiamata " Test " alla richiesta, ma ovviamente possiamo diventare complessi quanto ci serve per aumentare le nostre richieste.

8. Prova il filtro Zuul personalizzato

Infine, testiamo assicurandoci che il nostro filtro personalizzato funzioni: prima modificheremo il nostro FooController sul server di risorse Foos:

@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")); } return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4)); } }

Ora, proviamolo:

@Test public void whenSendRequest_thenHeaderAdded() { Response response = RestAssured.get("//localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); assertEquals("TestSample", response.getHeader("Test")); }

9. Conclusione

In questo articolo, ci siamo concentrati sull'utilizzo di Zuul per instradare le richieste da un'applicazione dell'interfaccia utente a un'API REST. Abbiamo lavorato con successo intorno a CORS e alla policy della stessa origine e siamo anche riusciti a personalizzare e aumentare la richiesta HTTP in transito.

L' implementazione completa di questo tutorial può essere trovata nel progetto GitHub: questo è un progetto basato su Maven, quindi dovrebbe essere facile da importare ed eseguire così com'è.