Spring REST avec un proxy Zuul

1. Vue d'ensemble

Dans cet article, nous allons explorer la communication entre une application frontale et une API REST qui sont déployées séparément .

L'objectif est de contourner CORS et la restriction de la politique de même origine du navigateur et de permettre à l'interface utilisateur d'appeler l'API même si elles ne partagent pas la même origine.

Nous allons essentiellement créer deux applications distinctes - une application d'interface utilisateur et une API REST simple, et nous utiliserons le proxy Zuul dans l'application d'interface utilisateur pour proxy les appels à l'API REST.

Zuul est un routeur basé sur JVM et un équilibreur de charge côté serveur de Netflix. Et Spring Cloud a une belle intégration avec un proxy Zuul intégré - ce que nous utiliserons ici.

2. Configuration Maven

Tout d' abord, nous devons ajouter une dépendance au soutien Zuul du printemps Cloud de notre application de l' interface utilisateur pom.xml :

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

La dernière version peut être trouvée ici.

3. Propriétés Zuul

Ensuite, nous devons configurer Zuul, et puisque nous utilisons Spring Boot, nous allons le faire dans l' application.yml :

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

Notez que:

  • Nous envoyons un proxy à notre serveur de ressources Foos.
  • Toutes les demandes de l'interface utilisateur commençant par " / foos / " seront acheminées vers notre serveur de ressources Foos à l' adresse // loclahost: 8081 / spring-zuul-foos-resource / foos /

4. L'API

Notre application API est une simple application Spring Boot.

Dans cet article, nous allons considérer l'API déployée sur un serveur fonctionnant sur le port 8081.

Définissons d'abord le DTO de base pour la ressource que nous allons utiliser:

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

Et un simple contrôleur:

@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'application UI

Notre application d'interface utilisateur est également une simple application Spring Boot.

Dans cet article, nous allons considérer l'API déployée sur un serveur fonctionnant sur le port 8080.

Commençons par le principal index.html - en utilisant un peu d'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'aspect le plus important ici est la façon dont nous accédons à l'API en utilisant des URL relatives!

Gardez à l'esprit que l'application API n'est pas déployée sur le même serveur que l'application d'interface utilisateur, les URL relatives ne devraient donc pas fonctionner et ne fonctionneront pas sans le proxy.

Avec le proxy, cependant, nous accédons aux ressources Foo via le proxy Zuul, qui est bien sûr configuré pour acheminer ces requêtes vers l'endroit où l'API est réellement déployée.

Et enfin, l'application réellement activée au démarrage:

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

Au-delà de la simple annotation de démarrage, notez que nous utilisons également le style d'annotation d'activation pour le proxy Zuul, qui est plutôt cool, propre et concis.

6. Testez le routage

Maintenant - testons notre application d'interface utilisateur - comme suit:

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

7. Un filtre Zuul personnalisé

Il existe plusieurs filtres Zuul disponibles, et nous pouvons également créer notre propre filtre personnalisé:

@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; } // ... }

Ce filtre simple ajoute simplement un en-tête appelé « Test » à la requête - mais bien sûr, nous pouvons devenir aussi complexes que nécessaire pour augmenter ici nos requêtes.

8. Test du filtre Zuul personnalisé

Enfin, testons nous assurer que notre filtre personnalisé fonctionne - nous allons d'abord modifier notre serveur de ressources FooController sur 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)); } }

Maintenant - testons-le:

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

9. Conclusion

Dans cet article, nous nous sommes concentrés sur l'utilisation de Zuul pour acheminer les demandes d'une application d'interface utilisateur vers une API REST. Nous avons travaillé avec succès autour de CORS et de la politique de même origine et nous avons également réussi à personnaliser et à augmenter la requête HTTP en transit.

L' implémentation complète de ce didacticiel se trouve dans le projet GitHub - il s'agit d'un projet basé sur Maven, il devrait donc être facile à importer et à exécuter tel quel.