Spring REST 與 Zuul 代理


http://www.baeldung.com/spring-rest-with-zuul-proxy
作者: Eugen Paraschiv
譯者: http://oopsguy.com

1、概述

在本文中,我們將探討前端應用與單獨部署的 REST API 之間的通信。

本文旨在解決 CORS 和瀏覽器的同源策略限制,允許 UI 調用 API,即使它們不是同源

基本上,我們將創建兩個獨立的應用程序 — 一個 UI 應用程序和一個簡單的 REST API,我們將使用 UI 應用程序中的 Zuul 代理來代理對 REST API 的調用。

Zuul 是 Netflix 的一個基於 JVM 的路由和服務端負載均衡器。Spring Cloud 與內嵌式 Zuul 代理可以很好地集成工作 — 本次我們也將使用他們。

2、Maven 配置

首先,我們需要添加一個來自 Spring Cloud 的 zuul 支持到我們的 UI 應用程序的 pom.xml 中:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.0.4.RELEASE</version>
</dependency>

3、Zuul Properties

接下來,我們需要配置 Zuul,由於我們使用 Spring Boot,我們將在 application.yml 中進行配置:

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

注意:

  • 我們正在代理我們的資源服務器 Foos
  • /foos/ 開頭的 UI 的所有請求都將路由到我們的 Foos 資源服務器:http:// loclahost:8081/spring-zuul-foos-resource/foos/

4、API

我們的 API 應用程序是一個簡單的 Spring Boot 應用程序。

在本文中,我們考慮將 API 部署至運行在 8081 端口上的服務器中。

首先定義我們要使用的資源的 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));
    }
}

5、UI 應用程序

我們的 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 代理的注解啟用方式,這非常酷,而且干凈簡潔。

6、測試路由

現在,讓我們來測試 UI 應用程序,如下所示:

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

7、自定義 Zuul Filter

有多個 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 的頭部 — 當然,我們可以根據我們需要的復雜程度來擴充我們的請求。

8、測試自定義 Zuul Filter

最后,讓我們測試以確保我們自定義的過濾器能夠正常工作 — 首先我們將在 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"));
}

9、結論

在這篇文章中,我們主要使用了 Zuul 將來自 UI 應用程序的請求路由到 REST API。我們成功地解決了 CORS 和同源策略,我們還定制和擴充了 HTTP 請求。

本教程的完整實現可以在項目 GitHub 中找到 — 這是一個基於 Maven 的項目,所以應該很容易導入和運行。

原文項目示例代碼

https://github.com/eugenp/tutorials/tree/master/spring-zuul


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM