天天看點

Spring Cloud Netflix Zuul 服務網關

文章目錄

    • 1 概述
    • 2 準備工作
      • 2.1 服務注冊
      • 2.2 服務消費
    • 3 基本使用
    • 4 請求過濾
    • 5 其他配置
      • 5.1 比對規則
      • 5.2 忽略路徑
      • 5.3 字首

學習在 Spring Cloud 中使用 Zuul 實作服務網關,包括基本使用、請求過濾、忽略路徑、字首等功能。它是 Netflix 家族成員之一。

1 概述

由于每一個微服務的位址都有可能發生變化,無法直接對外公布這些服務位址,基于安全以及高内聚低耦合等設計,我們有必要将内部系統和外部系統做一個切割。

一個專門用來處理外部請求的元件,就是服務網關,常用功能:

  • 權限問題統一處理
  • 資料剪裁和聚合
  • 簡化用戶端的調用
  • 可以針對不同的用戶端提供不同的網關支援

在 Spring Cloud 中,網關主要有兩種實作方案:

Zuul

Spring Cloud Gateway

Zuul 是 Netflix 公司提供的網關服務,主要有如下功能:

  • 權限控制,可以做認證和授權
  • 監控
  • 動态路由
  • 負載均衡
  • 靜态資源處理

Zuul 中的功能基本上都是基于過濾器來實作,它的過濾器有幾種不同的類型:

  • PRE
  • ROUTING
  • POST
  • ERROR

2 準備工作

2.1 服務注冊

建立 Spring Boot 項目

zuul-client-provider

,作為我們的服務提供者,添加

Web/Eureka Client

依賴,如下:

Spring Cloud Netflix Zuul 服務網關

最終的依賴如下:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
           

項目建立成功後,修改

application.properties

配置檔案,将 zuul-client-provider 注冊到 Eureka Server 上(服務注冊中心使用 Eureka Server ),如下:

# 目前服務的名稱
spring.application.name=zuul-client-provider
# 目前服務的端口
server.port=6000

# 服務注冊中心位址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
           

接下來,啟動 Eureka Server ,待服務注冊中心啟動成功後,再啟動 zuul-client-provider ,兩者都啟動成功後,通路 http://127.0.0.1:1111 可以看到 zuul-client-provider 的注冊資訊。

當然 zuul-client-provider 也可以叢集化部署,下面對 zuul-client-provider 進行打包,之後我們在指令行啟動兩個 provider 執行個體:

java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6000
java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6001
           

最後在 zuul-client-provider 提供一個 hello 接口,用于後續服務消費者 zuul-client-consumer 來消費,如下:

@RestController
public class ProviderController {
    @Value("${server.port}")
    Integer port; // 支援啟動多個執行個體,做負載均衡,用端口區分

    @GetMapping("/hello")
    public String hello() {
        return "hello cxy35: " + port;
    }
}
           

2.2 服務消費

建立 Spring Boot 項目

zuul-client-consumer

,作為我們的服務消費者,添加

Web/Eureka Client/Zuul

依賴,如下:

Spring Cloud Netflix Zuul 服務網關

最終的依賴如下:

<dependencies>
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  </dependency>
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
  </dependency>

  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      <exclusions>
          <exclusion>
              <groupId>org.junit.vintage</groupId>
              <artifactId>junit-vintage-engine</artifactId>
          </exclusion>
      </exclusions>
  </dependency>
</dependencies>
           

項目建立成功後,修改

application.properties

配置檔案,将 zuul-client-consumer 注冊到 Eureka Server 上(服務注冊中心使用 Eureka Server ),如下:

# 目前服務的名稱
spring.application.name=zuul-client-consumer
# 目前服務的端口
server.port=6002

# 服務注冊中心位址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
           

接着,在項目啟動類上添加

@EnableZuulProxy

注解,開啟網關代理,如下:

@SpringBootApplication
@EnableZuulProxy // 開啟網關代理
public class ZuulClientConsumerApplication {

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

}
           

接下來,啟動 zuul-client-consumer ,通路 http://127.0.0.1:1111 可以看到 zuul-client-consumer 的注冊資訊。

3 基本使用

配置完成後,通路 http://127.0.0.1:6002/zuul-client-provider/hello ,會自動通過 Zuul 的代理通路到 zuul-client-provider 中對應的的接口,無需知道其真實的位址。在這個通路位址中, zuul-client-provider 就是要通路的服務名稱, /hello 則是要通路的服務接口。

當然, Zuul 中的路由規則也可以自己配置,如下:

# Zuul 中的路由規則配置
# zuul.routes.cxy35.path=/cxy35/**
# zuul.routes.cxy35.service-id=zuul-client-provider

# 簡化配置
zuul.routes.zuul-client-provider=/cxy35/**
           

上面配置表示滿足

/cxy35/**

這個比對規則的請求,将被轉發到 zuul-client-provider 執行個體上。比如:http://127.0.0.1:6002/cxy35/hello

4 請求過濾

對于來自用戶端的請求,可以在 Zuul 中進行預處理,例如權限判斷等。

zuul-client-consumer

中定義一個簡單的權限過濾器,如下:

@Component
public class PermissionFilter extends ZuulFilter {
    /**
     * 過濾器類型,權限判斷一般是 pre
     *
     * @return
     */
    @Override
    public String filterType() {
        return "pre";
    }

    /**
     * 過濾器優先級
     *
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否過濾
     *
     * @return
     */


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

    /**
     * 核心的過濾邏輯寫在這裡
     *
     * @return 這個方法雖然有傳回值,但是這個傳回值目前無所謂
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();//擷取目前請求
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if (!"cxy35".equals(username) || !"123456".equals(password)) {
            //如果請求條件不滿足的話,直接從這裡給出響應
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            ctx.addZuulResponseHeader("content-type", "text/html;charset=utf-8");
            ctx.setResponseBody("非法通路,無權限");
        }
        return null;
    }
}
           

重新開機 zuul-client-consumer ,接下來,發送請求必須帶上 username 和 password 參數,否則請求不通過,比如:http://127.0.0.1:6002/cxy35/hello?username=cxy35&password=123456

5 其他配置

5.1 比對規則

例如有兩個服務,一個叫 provider ,另一個叫 provider-hello ,在做路由規則設定時,假如出現了如下配置:

zuul.routes.provider=/provider/**

zuul.routes.provider-hello=/provider/hello/**
           

此時,如果通路一個位址:

http://127.0.0.1:6002/provider/hello/123

,會出現沖突。實際上,這個位址是希望和 provider-hello 這個服務比對的,這個時候,隻需要把配置檔案改為 yml 格式就可以了,因為 yml 格式的配置是有序的。

5.2 忽略路徑

預設情況下,Zuul 注冊到 Eureka 上之後, Eureka 上的所有注冊服務都會被自動代理。如果不想給某一個服務做代理,可以忽略該服務,配置如下:

zuul.ignored-services=provider2
           

上面這個配置表示忽略 provider2 服務,此時就不會自動代理 provider2 服務了。

當然,也可以忽略某一類位址,配置如下:

zuul.ignored-patterns=/**/hello/**
           

這個表示請求路徑中如果包含 hello ,則不做代理。

5.3 字首

可以統一給路由加字首,配置如下:

zuul.prefix=/cxy35
           

這樣,以後所有的請求位址自動多了字首

/cxy35

  • Spring Cloud 教程合集(微信左下方閱讀全文可直達)。
  • Spring Cloud 教程合集示例代碼:https://github.com/cxy35/spring-cloud-samples
  • 本文示例代碼:https://github.com/cxy35/spring-cloud-samples/tree/master/spring-cloud-zuul

掃碼關注微信公衆号 程式員35 ,擷取最新技術幹貨,暢聊 #程式員的35,35的程式員# 。獨立站點:https://cxy35.com

Spring Cloud Netflix Zuul 服務網關

繼續閱讀