Spring REST 與 Zuul 代理

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

二、Maven 配置

首先,咱們須要添加一個來自 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 Properties

接下來,咱們須要配置 Zuul,因爲咱們使用 Spring Boot,咱們將在 application.yml 中進行配置:api

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/

四、API

咱們的 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 應用程序

咱們的 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 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 的頭部 — 固然,咱們能夠根據咱們須要的複雜程度來擴充咱們的請求。

八、測試自定義 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"));
}

九、結論

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

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

原文項目示例代碼

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

相關文章
相關標籤/搜索