http://www.baeldung.com/spring-rest-with-zuul-proxy
做者: Eugen Paraschiv
譯者: http://oopsguy.comhtml
在本文中,咱們將探討前端應用與單獨部署的 REST API 之間的通訊。前端
本文旨在解決 CORS 和瀏覽器的同源策略限制,容許 UI 調用 API,即便它們不是同源。java
基本上,咱們將建立兩個獨立的應用程序 — 一個 UI 應用程序和一個簡單的 REST API,咱們將使用 UI 應用程序中的 Zuul 代理來代理對 REST API 的調用。git
Zuul 是 Netflix 的一個基於 JVM 的路由和服務端負載均衡器。Spring Cloud 與內嵌式 Zuul 代理能夠很好地集成工做 — 本次咱們也將使用他們。github
首先,咱們須要添加一個來自 Spring Cloud 的 zuul 支持到咱們的 UI 應用程序的 pom.xml 中:spring
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> <version>1.0.4.RELEASE</version> </dependency>
接下來,咱們須要配置 Zuul,因爲咱們使用 Spring Boot,咱們將在 application.yml 中進行配置:api
zuul: routes: foos: path: /foos/** url: http://localhost:8081/spring-zuul-foos-resource/foos
注意:瀏覽器
咱們的 API 應用程序是一個簡單的 Spring Boot 應用程序。服務器
在本文中,咱們考慮將 API 部署至運行在 8081 端口上的服務器中。app
首先定義咱們要使用的資源的 DTO:
public class Foo { private long id; private String name; // standard getters and setters }
和一個簡單的控制器:
@Controller public class FooController { @RequestMapping(method = RequestMethod.GET, value = "/foos/{id}") @ResponseBody public Foo findById( @PathVariable long id, HttpServletRequest req, HttpServletResponse res) { return new Foo(Long.parseLong(randomNumeric(2)), randomAlphabetic(4)); } }
咱們的 UI 應用程序也是一個簡單的 Spring Boot 應用程序。
在本文中,咱們考慮將 UI 部署至運行在 8080 端口上的服務器中。
咱們從 index.html 開始 — 使用了一點 AngularJS:
<html> <body ng-app="myApp" ng-controller="mainCtrl"> <script src="angular.min.js"></script> <script src="angular-resource.min.js"></script> <script> 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}); } }); </script> <div> <h1>Foo Details</h1> <span>{{foo.id}}</span> <span>{{foo.name}}</span> <a href="#" ng-click="getFoo()">New Foo</a> </div> </body> </html>
這裏最重要的地方是咱們如何使用相對 URL 來訪問 API!
請記住,API 應用程序未部署在與 UI 應用程序相同的服務器上,所以沒法經過相對 URL 工做,若是沒有使用代理,該 UI 應用程序將沒法正常工做。
然而,若是使用代理服務器,咱們能夠經過 Zuul 代理來訪問 Foo 資源,該代理配置爲將這些請求路由到實際部署 API 的位置。
最後,引導應用程序:
@EnableZuulProxy @SpringBootApplication public class UiApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(UiApplication.class, args); } }
除了簡單的引導註解,請注意,咱們使用 Zuul 代理的註解啓用方式,這很是酷,並且乾淨簡潔。
如今,讓咱們來測試 UI 應用程序,以下所示:
@Test public void whenSendRequestToFooResource_thenOK() { Response response = RestAssured.get("http://localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); }
有多個 Zuul 過濾器可使用,咱們也能夠建立本身自定義的過濾器:
@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; } // ... }
這個簡單的過濾器只是在請求中添加了一個名爲 Test 的頭部 — 固然,咱們能夠根據咱們須要的複雜程度來擴充咱們的請求。
最後,讓咱們測試以確保咱們自定義的過濾器可以正常工做 — 首先咱們將在 Foos 資源服務器上修改 FooController:
@Controller public class FooController { @GetMapping("/foos/{id}") @ResponseBody 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)); } }
如今,讓咱們開始測試:
@Test public void whenSendRequest_thenHeaderAdded() { Response response = RestAssured.get("http://localhost:8080/foos/1"); assertEquals(200, response.getStatusCode()); assertEquals("TestSample", response.getHeader("Test")); }
在這篇文章中,咱們主要使用了 Zuul 未來自 UI 應用程序的請求路由到 REST API。咱們成功地解決了 CORS 和同源策略,咱們還定製和擴充了 HTTP 請求。
本教程的完整實現能夠在項目 GitHub 中找到 — 這是一個基於 Maven 的項目,因此應該很容易導入和運行。