1. 程式人生 > >Spring Cloud中的API閘道器服務Zuul (13)

Spring Cloud中的API閘道器服務Zuul (13)

轉自 https://blog.csdn.net/u012702547/article/details/77823434

這個系列我感覺真的太好了,可以一步一步的瞭解spring cloud 的搭建以及更深層次的東西,對想學這門技術的朋友真的入門特別的快,感謝這位大哥的分享,我也會持續的更新過來。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------

到目前為止,我們Spring Cloud中的內容已經介紹了很多了,Ribbon、Hystrix、Feign這些知識點大家都耳熟能詳了,我們在前文也提到過微服務就是把一個大的專案拆分成很多小的獨立模組,然後通過服務治理讓這些獨立的模組配合工作等。那麼大家來想這樣兩個問題:1.如果我的微服務中有很多個獨立服務都要對外提供服務,那麼對於開發人員或者運維人員來說,他要如何去管理這些介面?特別是當專案非常大非常龐雜的情況下要如何管理?2.許可權管理也是一個老生常談的問題,在微服務中,一個獨立的系統被拆分成很多個獨立的模組,為了確保安全,我難道需要在每一個模組上都新增上相同的鑑權程式碼來確保系統不被非法訪問?如果是這樣的話,那麼工作量就太大了,而且維護也非常不方便。

為了解決上面提到的問題,我們引入了API閘道器的概念,API閘道器是一個更為智慧的應用伺服器,它有點類似於我們微服務架構系統的門面,所有的外部訪問都要先經過API閘道器,然後API閘道器來實現請求路由、負載均衡、許可權驗證等功能。Spring Cloud中提供的Spring Cloud Zuul實現了API閘道器的功能,本文我們就先來看看Spring Cloud Zuul的一個基本使用。


本文是Spring Cloud系列的第十九篇文章,瞭解前十八篇文章內容有助於更好的理解本文:

1.使用Spring Cloud搭建服務註冊中心 
2.使用Spring Cloud搭建高可用服務註冊中心

 
3.Spring Cloud中服務的發現與消費 
4.Eureka中的核心概念 
5.什麼是客戶端負載均衡 
6.Spring RestTemplate中幾種常見的請求方式 
7.RestTemplate的逆襲之路,從傳送請求到負載均衡 
8.Spring Cloud中負載均衡器概覽 
9.Spring Cloud中的負載均衡策略 
10.Spring Cloud中的斷路器Hystrix 
11.Spring Cloud自定義Hystrix請求命令 
12.Spring Cloud中Hystrix的服務降級與異常處理 
13.Spring Cloud中Hystrix的請求快取 
14.Spring Cloud中Hystrix的請求合併 
15.Spring Cloud中Hystrix儀表盤與Turbine叢集監控 
16.Spring Cloud中宣告式服務呼叫Feign 
17.Spring Cloud中Feign的繼承特性 
18.Spring Cloud中Feign配置詳解


構建閘道器

閘道器的構建我們通過下面三個步驟來實現。

1.建立Spring Boot工程並新增依賴

首先我們建立一個普通的Spring Boot工程名為api-gateway,然後新增相關依賴,這裡我們主要新增兩個依賴spring-cloud-starter-zuul和spring-cloud-starter-eureka,spring-cloud-starter-zuul依賴中則包含了ribbon、hystrix、actuator等,如下:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.添加註解

然後在入口類上新增@EnableZuulProxy註解表示開啟Zuul的API閘道器服務功能,如下:

@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

3.配置路由規則

application.properties檔案中的配置可以分為兩部分,一部分是Zuul應用的基礎資訊,還有一部分則是路由規則,如下:

# 基礎資訊配置
spring.application.name=api-gateway
server.port=2006
# 路由規則配置
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=feign-consumer

# API閘道器也將作為一個服務註冊到eureka-server上
eureka.client.service-url.defaultZone=http://localhost:1111/eureka/

我們在這裡配置了路由規則所有符合/api-a/**的請求都將被轉發到feign-consumer服務上,至於feign-consumer服務的地址到底是什麼則由eureka-server去分析,我們這裡只需要寫上服務名即可。以上面的配置為例,如果我請求http://localhost:2006/api-a/hello1介面則相當於請求http://localhost:2005/hello1(我這裡feign-consumer的地址為http://localhost:2005),我們在路由規則中配置的api-a是路由的名字,可以任意定義,但是一組path和serviceId對映關係的路由名要相同。

OK,做好這些之後,我們依次啟動我們的eureka-server、provider和feign-consumer,然後訪問如下地址http://localhost:2006/api-a/hello1,訪問結果如下:

這裡寫圖片描述

看到這個效果說明我們的API閘道器服務已經構建成功了,我們傳送的符合路由規則的請求自動被轉發到相應的服務上去處理了。

請求過濾

構建好了閘道器,接下來我們就來看看如何利用閘道器來實現一個簡單的許可權驗證。這裡就涉及到了Spring Cloud Zuul中的另外一個核心功能:請求過濾。請求過濾有點類似於Java中Filter過濾器,先將所有的請求攔截下來,然後根據現場情況做出不同的處理,這裡我們就來看看Zuul中的過濾器要如何使用。很簡單,兩個步驟:

1.定義過濾器

首先我們定義一個過濾器繼承自ZuulFilter,如下:

public class PermisFilter extends ZuulFilter {
    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String login = request.getParameter("login");
        if (login == null) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.addZuulResponseHeader("content-type","text/html;charset=utf-8");
            ctx.setResponseBody("非法訪問");
        }
        return null;
    }
}

關於這個類我說如下幾點:

1.filterType方法的返回值為過濾器的型別,過濾器的型別決定了過濾器在哪個生命週期執行,pre表示在路由之前執行過濾器,其他可選值還有post、error、route和static,當然也可以自定義。 
2.filterOrder方法表示過濾器的執行順序,當過濾器很多時,這個方法會有意義。 
3.shouldFilter方法用來判斷過濾器是否執行,true表示執行,false表示不執行,在實際開發中,我們可以根據當前請求地址來決定要不要對該地址進行過濾,這裡我直接返回true。 
4.run方法則表示過濾的具體邏輯,假設請求地址中攜帶了login引數的話,則認為是合法請求,否則就是非法請求,如果是非法請求的話,首先設定ctx.setSendZuulResponse(false);表示不對該請求進行路由,然後設定響應碼和響應值。這個run方法的返回值在當前版本(Dalston.SR3)中暫時沒有任何意義,可以返回任意值。

2.配置過濾器Bean

然後在入口類中配置相關的Bean即可,如下:

@Bean
PermisFilter permisFilter() {
    return new PermisFilter();
}

此時,如果我們訪問http://localhost:2006/api-a/hello1,結果如下:

這裡寫圖片描述

如果給請求地址加上login引數,則結果如下:

這裡寫圖片描述

總結

到這裡小夥伴們應該已經見識到Spring Cloud Zuul的強大之處了吧,API閘道器作為系統的的統一入口,將微服務中的內部細節都遮蔽掉了,而且能夠自動的維護服務例項,實現負載均衡的路由轉發,同時,它提供的過濾器為所有的微服務提供統一的許可權校驗機制,使得服務自身只需要關注業務邏輯即可。

Zuul的入門知識我們就先介紹到這裡,小夥伴們有問題歡迎留言討論。