1. 程式人生 > >spring cloud 入門系列六:使用Zuul 實現API閘道器服務

spring cloud 入門系列六:使用Zuul 實現API閘道器服務

通過前面幾次的分享,我們瞭解了微服務架構的幾個核心設施,通過這些元件我們可以搭建簡單的微服務架構系統。比如通過Spring Cloud Eureka搭建高可用的服務註冊中心並實現服務的註冊和發現;

通過Spring Cloud Ribbon或Feign進行負載均衡;通過Spring Cloud Hystrix進行服務容錯保護以避免故障蔓延。微服務搭建好了之後我們肯定會提供給外部系統一些統一的RESTFul API服務介面進行呼叫,

但是當外部系統呼叫我們的RESTful API的時候,怎麼確定它需要的功能具體是哪個服務提供的呢?這個就涉及到一個路由規則和服務例項列表的維護問題。

這就引入了我們今天的主角--Spring Cloud Zuul,它是基於Netflix Zuul實現的API閘道器元件。它可以解決兩個大問題:

  1. 就是我們上面提到的路由規則和服務例項的維護問題
  2. 對於一些校驗(比如登入校驗等)冗餘問題。 按照我們的習慣的做法,是在每個服務中都需要加入這些校驗,但是這樣會導致程式碼冗餘並且維護也比較麻煩,有了Spring Cloud Zuul這個閘道器服務之後,我們可以將這些共通的校驗放到閘道器裡面統一維護。

好,接下來我們就來看下怎麼實現這個閘道器服務。

一、構建閘道器,配置路由

 這裡我們還是需要使用到前面的hello-service和feign-consumer服務。我們之前把feign-consumer作為服務消費者,但是別忘了在eureka體系裡面,每個服務既是服務提供者又是服務消費者,所以feign-consumer也是一個服務提供者,並且http://localhost:9001/feign-consumer等介面就是它提供的服務。

接下來我們構建一個閘道器服務,程式碼結構如下:

  

程式碼實現步驟:

  1. 新建maven工程api-gateway
  2. 修改POM檔案
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion
    > <groupId>com.sam</groupId> <artifactId>api-gateway</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> </parent> <properties> <javaVersion>1.8</javaVersion> </properties> <!-- 使用dependencyManagement進行版本管理 --> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <!-- 引入zuul依賴 , 它依賴了spring-boot-starter-actuator/spring-boot-starter-hystrix/spring-boot-starter-ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> </dependencies> </project>
  3. 新建啟動類
    /**
     * @EnableZuulProxy 開啟Zuul 的API閘道器服務功能
     *
     */
    @EnableZuulProxy
    @SpringCloudApplication
    public class GateWayApp {
    
        public static void main(String[] args) {
            SpringApplication.run(GateWayApp.class, args);
        }
    }
  4. 新建application.properties
    server.port=5555
    spring.application.name=api-gateway
    
    #增加路由規則的配置
    #通過zuul.routes.<route>.path和zuul.routes.<route>.url進行配置,<route>為路由的名字,可以任意指定,但是一組path和url的路由名要相同
    #如下面的例子:所有滿足/api-a/** 規則的訪問都會被路由轉發到//localhost:9001的地址
    #也就是說,我們訪問http://localhost:5555/api-a/hello的時候,API閘道器服務就會將該請#求路由到 http://localhost:9001/hello提供的微服務介面上
    zuul.routes.api-a.path=/api-a/**
    zuul.routes.api-a.url=http://localhost:9001
    
    
    zuul.routes.api-b.path=/api-b/**
    zuul.routes.api-b.url=http://localhost:9090
  5. 測試,啟動eureka、hello-service、feign-consumer以及本次新加的api-gateway服務,然後訪問http://localhost:5555/api-a/feign-consumer

    成功訪問到了feign-consumer的服務介面--feign-consonsumer。

以上步驟實現了傳統路由的配置,這種配置有個大的缺點,就是需要手工在application.properties檔案中進行路由規則的配置,當服務很多的時候,維護工作量就會很大。為了減小維護成本,還有另外一種路由--面向服務的路由。

二、面向服務的路由

Spring Cloud Zuul和Eureka進行整合,我們可以讓路由的path不是對映具體的url,而是具體的某個服務,而服務的url則交給Eureka服務發現機制自動維護,這類路由就是面向服務的路由。具體程式碼配置如下:

  1. 修改POM檔案,引入Eureka依賴
    <!-- 引入eureka依賴 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
  2. 修改application.properties配置檔案
    server.port=5555
    spring.application.name=api-gateway
    
    zuul.routes.api-a.path=/api-a/**
    
    #這裡用serviceId代替url,用服務名代替ip+埠號
    zuul.routes.api-a.serviceId=hello-service

    eureka.client.service-url.defaultZone=http://localhost:1111/eureka

    注意:zuul.routes.api-a.url=hello-service也能實現功能,但是它不能進行正常的負載均衡和容錯保護。

  3. 測試,訪問http://localhost:5555/api-a/hello

    訪問成功。

 三、服務路由的預設規則

在面向服務的路由中,由於<route>名字是隨意起的,那麼是不是可以這樣:

zuul.routes.hello-service.path=/hello-service/**
zuul.routes.hello-service.serviceId=hello-service

<route>名字就是服務名,其實在實際的應用中,我們往往就是這樣命名的。如果有這樣的規則的話,那Zuul就可以幫我們預設實現這樣的功能,進一步省去了配置的麻煩。

我們來做個實驗,將配置檔案改為:

server.port=5555
spring.application.name=api-gateway

eureka.client.service-url.defaultZone=http://localhost:1111/eureka

然後頁面訪問驗證

訪問成功。

但是由於預設情況下,Eureka上的服務都會被Zuul建立預設的對映關係來進行路由,使得我們不想對外開放的服務也被外部訪問到,這個時候可以通過配置zuul.ignored-services來進行配置不需要自動建立路由的規則。當zuul.ignored-services=*的時候,所有的服務都不會自動建立路由規則,這個時候需要通過前面的配置進行相關路由配置了。

================華麗的分割線===================

前面說了那麼多都是圍繞一個問題展開的:路由規則和服務例項的維護問題,那麼怎麼解決第二個問題(校驗冗餘問題)呢?

 四、請求過濾

為了在API閘道器中實現對客戶端請求的校驗,我們可以通過過濾器來實現對請求的攔截和過濾,實現方法比較簡單,只需要繼承ZuulFilter抽象類並實現其四個方法就行了。

修改api-gateway:

  1. 新增過濾器類
    /**
     * 繼承ZuulFilter,並且實現其4個介面
     *
     * 用來進行請求過濾
     *
     */
    public class AccessFilter extends ZuulFilter {
        Logger logger = LoggerFactory.getLogger(AccessFilter.class);
        /* 
         * shouldFilter 判斷該過濾器是否需要被執行
         * 
         * 這裡直接返回true,表示該過濾器對所有請求都會生效。
         * 實際運用中我們可以利用該函式指定過濾器的有效範圍
         */
        @Override
        public boolean shouldFilter() {
            return true;
        }
    
        /*
         * 過濾器的具體邏輯
         * 
         * 這裡我們通過ctx.setSendZuulResponse(false)讓zuul過來請求,不對其進行路由
         * 然後通過ctx.setResponseStatusCode(401)設定了返回的錯誤碼
         * 
         */
        @Override
        public Object run() {
            RequestContext context = RequestContext.getCurrentContext();
            HttpServletRequest request = context.getRequest();
            Object accessToken = request.getParameter("accessToken");
            
            logger.info("send {} request to {}", request.getMethod(),request.getRequestURL().toString());
            if(accessToken == null) {
                context.setSendZuulResponse(false);
                context.setResponseStatusCode(401);
            }
            
            return null;
        }
    
        /* filterType 返回過濾器型別
         * 他決定了過濾器在請求的哪個生命週期中執行。這裡定義為pre,代表會在請求被路由前執行。
         * 
         * pre:請求執行之前filter 
         * route: 處理請求,進行路由 
         * post: 請求處理完成後執行的filter 
         * error:出現錯誤時執行的filter
         */
        @Override
        public String filterType() {
            return "pre";
        }
        
        
        /* 
         * filterOrder 返回過濾器的執行順序
         * 
         * 當請求在一個階段有多個過濾器是,需要根據該方法的返回值來依次執行
         * 
         */
        @Override
        public int filterOrder() {
            return 0;
        }
    
    }
  2. 修改啟動類
    /**
     * @EnableZuulProxy 開啟Zuul 的API閘道器服務功能
     *
     */
    @EnableZuulProxy
    @SpringCloudApplication
    public class GateWayApp {
    
        //追加bean的是實現
        @Bean
        public AccessFilter accessFilter() {
            return new AccessFilter();
        }
        
        public static void main(String[] args) {
            SpringApplication.run(GateWayApp.class, args);
        }
    }
  3. 測試
    1. )訪問http://localhost:5555/hello-service/hello,訪問失敗
    2. )訪問http://localhost:5555/hello-service/hello?accessToken=token,正常訪問

修改後的程式碼結構:

 五、拓展延伸

其實路由功能在真正執行時,他的路由對映和請求轉發都是由幾個不同的過濾器完成的。

路由對映主要通過pre型別的過濾器完成,他將請求路徑與配置的路由規則進行匹配,找到需要轉發的目標地址。

而請求轉發的部分則是由route型別的過濾器完成的,對pre型別過濾器獲取的路由地址進行轉發。

所以,過濾器可以說是Zuul實現API閘道器功能最為核心的部件,每一個進入Zuul的HTTP請求都會經過一系列的過濾器處理鏈得到請求響應並返回給客戶端。

相關推薦

spring cloud 入門系列使用Zuul 實現API服務

通過前面幾次的分享,我們瞭解了微服務架構的幾個核心設施,通過這些元件我們可以搭建簡單的微服務架構系統。比如通過Spring Cloud Eureka搭建高可用的服務註冊中心並實現服務的註冊和發現; 通過Spring Cloud Ribbon或Feign進行負載均衡;通過Spring Cloud Hyst

Spring Cloud系列(二十三) API服務Spring Cloud Zuul(Finchley.RC2版本)

為什麼使用Spring Cloud Zuul? 通過前幾章的介紹,我們對於Spring Cloud Netflix 下的核心元件已經瞭解了大半,利用這些元件我們已經可以構建一個簡單的微服務架構系統,比如通過使用Spring Cloud Eureka實現高可用的服務註冊中

Spring Cloud ZuulAPI服務)(3)

過濾器 在Spring Cloud Zuul中實現的過濾器必須包含4個基本特徵:過濾型別,執行順序,執行條件,具體操作。這就是ZuulFilter介面中定義的4個抽象方法: public abstract String filterType(); public abst

Spring Cloud ZuulAPI服務)(2)

路由詳情 傳統路由配置 傳統路由配置方式就是在不依賴與服務發現機制的情況下,通過在配置檔案中具體指定每個路由表示式與服務例項的對映關係來實現API閘道器對外部請求的路由。 單例項配置:通過zuul.routes.<route>.path與zuul.routes.<r

Spring Cloud ZuulAPI服務)(1)

API閘道器是一個智慧的應用伺服器,它的定義類似於面向物件設計模式中的Facade模式,它的存在就像是整個微服務架構系統的門面一樣,所有的外部客戶端訪問都需要經過他來進行排程和過濾。它除了要實現請求路由,負載均衡,校驗過濾等功能之外,還需要更多能力,比如與服務治理框架的結合,請求轉發時的熔斷機制

hystri斷路器+zuul實現ApI+Sidecar異構系統呼叫NodeJS

hystri斷路器:豪豬 代表了一種防禦機制 分散式系統中,依賴呼叫失敗是不可避免的,為了避免一個依賴影響全域性 Netfilx團隊開發了Hystrix,hystrix提供了熔斷 、隔離、fallback、cache、監控等功能,能在一個一個依賴出問題的情況下保證系統可用 請求合併 將一

.NET Core微服務之基於Ocelot實現API服務

一、啥是API閘道器?   API 閘道器一般放到微服務的最前端,並且要讓API 閘道器變成由應用所發起的每個請求的入口。這樣就可以明顯的簡化客戶端實現和微服務應用程式之間的溝通方式。以前的話,客戶端不得不去請求微服務A(假設為Customers),然後再到微服務B(假設為Orders),然後是微服

.NET Core微服務之基於Ocelot實現API服務(續)

一、負載均衡與請求快取 1.1 負載均衡   為了驗證負載均衡,這裡我們配置了兩個Consul Client節點,其中ClientService分別部署於這兩個節點內(192.168.80.70與192.168.80.71)。   為了更好的展示API Repsonse來自哪個節點,我們更改一下

Spring Cloud系列教程 | 第Spring Cloud Zuul作為API實現請求路由轉發教程

推薦 Spring Cloud 視訊: Spring Cloud Zuul作為API閘道器實現請求路由轉發教程      當我們的架構實現前後端分離以後,前端和後端之間互動就是通過API閘道器進行,API閘道器兩個職責: 1.設計上的適配層,或稱Facade模

spring cloud 入門系列使用Hystrix 實現斷路器進行服務容錯保護

關系 調用 說明 schema 技術 能力 BE 最終 響應 在微服務中,我們將系統拆分為很多個服務單元,各單元之間通過服務註冊和訂閱消費的方式進行相互依賴。但是如果有一些服務出現問題了會怎麽樣? 比如說有三個服務(ABC),A調用B,B調用C。由於網絡延遲或C本身代碼有

spring cloud 入門系列使用Feign 實現宣告式服務呼叫

一、Spring Cloud Feign概念引入通過前面的隨筆,我們瞭解如何通過Spring Cloud ribbon進行負責均衡,如何通過Spring Cloud Hystrix進行服務斷路保護,兩者作為基礎工具類框架應用在各種基礎設施類微服務和業務類微服務中,並且成對存在,那麼有沒有更高層的封裝,將兩者的

spring cloud 入門系列基於Git存儲的分布式配置中心--Spring Cloud Config

入門 代碼結構 dev eas TP scope ict AI 新項目 我們前面接觸到的spring cloud組件都是基於Netflix的組件進行實現的,這次我們來看下spring cloud 團隊自己創建的一個全新項目:Spring Cloud Config.它用來為分

Spring Cloud 入門教程(五) Ribbon實現客戶端的負載均衡

接上節,假如我們的Hello world服務的訪問量劇增,用一個服務已經無法承載, 我們可以把Hello World服務做成一個叢集。  很簡單,我們只需要複製Hello world服務,同時將原來的埠8762修改為8763。然後啟動這兩個Spring Boot應用, 就可

Spring Cloud 入門教程() 用宣告式REST客戶端Feign呼叫遠端HTTP服務

首先簡單解釋一下什麼是宣告式實現? 要做一件事, 需要知道三個要素,where, what, how。即在哪裡( where)用什麼辦法(how)做什麼(what)。什麼時候做(when)我們納入how的範疇。 1)程式設計式實現: 每一個要素(where,wh

spring cloud 入門系列使用Eureka 進行服務治理

服務治理可以說是微服務架構中最為核心和基礎的模組,它主要用來實現各個微服務例項的自動化註冊和發現。 Spring Cloud Eureka是Spring Cloud Netflix 微服務套件的一部分,主要負責完成微服務架構中的服務治理功能。 本文通過簡單的小例子來分享下如何通過Eureka進行服務治理:

spring cloud 入門系列基於Git儲存的分散式配置中心--Spring Cloud Config

我們前面接觸到的spring cloud元件都是基於Netflix的元件進行實現的,這次我們來看下spring cloud 團隊自己建立的一個全新專案:Spring Cloud Config.它用來為分散式系統中的基礎設施和微服務提供集中化的外部配置支援,分為服務端和客戶端兩個部分。 其中服務端也稱為分散式

spring cloud 入門系列初識spring cloud

最近看到微服務很火,也是未來的趨勢, 所以就去學習下,在dubbo和spring cloud之間我選擇了從spring cloud,主要有如下幾種原因: dubbo主要專注於微服務中的一個環節--服務治理,像服務註冊和發現這種還需要zookeeper第三方的中間;但是spring cloud提供了微服

spring cloud 入門系列使用Eureka 搭建高可用服務註冊中心

在上一篇中分享了如何使用Eureka 進行服務治理,裡面搭建的服務註冊中心是單體的, 但是在實際的應用中,分散式系統為了防止單體服務宕機帶來嚴重後果,一般都會採用伺服器叢集的形式,服務註冊中心也是一樣,需要多臺服務一起工作,組成高可用的服務註冊中心。這樣,如果有其中一臺宕機,系統也能正常執行。 那麼如何來

spring cloud 入門系列使用spring cloud sleuth整合zipkin進行服務鏈路追蹤

好久沒有寫部落格了,主要是最近有些忙,今天忙裡偷閒來一篇。 =======我是華麗的分割線========== 微服務架構是一種分散式架構,微服務系統按照業務劃分服務單元,一個微服務往往會有很多個服務單元,一個請求往往會有很多個單元參與,一旦請求出現異常,想要去定位問題點真心不容易,因此需要有個東西去跟蹤

Spring Cloud入門API服務Spring Cloud Gateway)

文章例項使用的Spring Cloud版本為Finchley.SR1,Spring Boot版本為2.0.4。 1 Spring Cloud Gateway 在微服務架構中,閘道器作為服務的一個統一入口,所有的外部客戶端訪問都需要經過它來排程和過濾,可以實現的功能包括動