1. Información general
En este artículo, exploraremos la comunicación entre una aplicación front-end y una API REST que se implementan por separado .
El objetivo es evitar CORS y la restricción de la Política del mismo origen del navegador y permitir que la interfaz de usuario llame a la API aunque no compartan el mismo origen.
Básicamente, crearemos dos aplicaciones separadas: una aplicación de interfaz de usuario y una API REST simple, y usaremos el proxy Zuul en la aplicación de interfaz de usuario para llamadas proxy a la API REST.
Zuul es un enrutador basado en JVM y un equilibrador de carga del lado del servidor de Netflix. Y Spring Cloud tiene una buena integración con un proxy Zuul integrado, que es lo que usaremos aquí.
2. Configuración de Maven
Primero, necesitamos agregar una dependencia al soporte de zuul de Spring Cloud al pom.xml de nuestra aplicación de interfaz de usuario :
org.springframework.cloud spring-cloud-starter-netflix-zuul 2.2.0.RELEASE
La última versión se puede encontrar aquí.
3. Propiedades de Zuul
A continuación, necesitamos configurar Zuul, y como estamos usando Spring Boot, lo haremos en application.yml :
zuul: routes: foos: path: /foos/** url: //localhost:8081/spring-zuul-foos-resource/foos
Tenga en cuenta que:
- Estamos haciendo proxy a nuestro servidor de recursos Foos.
- Todas las solicitudes de la interfaz de usuario que comienzan con " / foos / " se enviarán a nuestro servidor de recursos Foos en // loclahost: 8081 / spring-zuul-foos-resource / foos /
4. La API
Nuestra aplicación API es una sencilla aplicación Spring Boot.
En este artículo, consideraremos la API implementada en un servidor que se ejecuta en el puerto 8081.
Primero definamos el DTO básico para el recurso que vamos a utilizar:
public class Foo { private long id; private String name; // standard getters and setters }
Y un controlador simple:
@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. La aplicación de interfaz de usuario
Nuestra aplicación de interfaz de usuario también es una sencilla aplicación Spring Boot.
En este artículo, consideraremos la API implementada en un servidor que se ejecuta en el puerto 8080.
Comencemos con el index.html principal , usando un poco de 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
El aspecto más importante aquí es cómo accedemos a la API usando URL relativas.
Tenga en cuenta que la aplicación API no se implementa en el mismo servidor que la aplicación UI, por lo que las URL relativas no deberían funcionar y no funcionarán sin el proxy.
Sin embargo, con el proxy, estamos accediendo a los recursos de Foo a través del proxy Zuul, que por supuesto está configurado para enrutar estas solicitudes a donde sea que la API esté realmente implementada.
Y finalmente, la aplicación realmente habilitada para arranque:
@EnableZuulProxy @SpringBootApplication public class UiApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(UiApplication.class, args); } }
Más allá de la simple anotación de arranque, observe que también estamos usando el estilo de anotación de habilitación para el proxy Zuul, que es bastante bueno, limpio y conciso.
6. Pruebe el enrutamiento
Ahora, probemos nuestra aplicación de interfaz de usuario de la siguiente manera:
@Test public void whenSendRequestToFooResource_thenOK() { Response response = RestAssured.get("//localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); }
7. Un filtro Zuul personalizado
Hay varios filtros Zuul disponibles, y también podemos crear uno personalizado:
@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; } // ... }
Este filtro simple simplemente agrega un encabezado llamado " Prueba " a la solicitud, pero, por supuesto, podemos volvernos tan complejos como sea necesario para aumentar nuestras solicitudes.
8. Pruebe el filtro Zuul personalizado
Finalmente, probemos para asegurarnos de que nuestro filtro personalizado esté funcionando; primero modificaremos nuestro FooController en el servidor de recursos de 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)); } }
Ahora, probémoslo:
@Test public void whenSendRequest_thenHeaderAdded() { Response response = RestAssured.get("//localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); assertEquals("TestSample", response.getHeader("Test")); }
9. Conclusión
En este artículo, nos enfocamos en usar Zuul para enrutar solicitudes desde una aplicación de interfaz de usuario a una API REST. Trabajamos con éxito en torno a CORS y la política del mismo origen y también logramos personalizar y aumentar la solicitud HTTP en tránsito.
La implementación completa de este tutorial se puede encontrar en el proyecto GitHub; este es un proyecto basado en Maven, por lo que debería ser fácil de importar y ejecutar tal como está.