史上最簡單的 SpringCloud 教程 | 第五篇: 路由閘道器 (zuul)

方誌朋發表於2019-03-04

轉載請標明出處:
blog.csdn.net/forezp/arti…
本文出自方誌朋的部落格

在微服務架構中,需要幾個關鍵的元件,服務註冊與發現、服務消費、負載均衡、斷路器、智慧路由、配置管理等,由這幾個元件可以組建一個簡單的微服務架構,如下圖:

史上最簡單的 SpringCloud 教程 | 第五篇: 路由閘道器 (zuul)
Azure (1).png

注意:A服務和B服務是可以相互呼叫的,作圖的時候忘記了。並且配置服務也是註冊到服務註冊中心的。

客戶端的請求首先經過負載均衡(zuul、Ngnix),再到達服務閘道器(zuul叢集),然後再到具體的服務,服務統一註冊到高可用的服務註冊中心叢集,服務的所有的配置檔案由配置服務管理(下一篇文章講述),配置服務的配置檔案放在git倉庫,方便開發人員隨時改配置。

一、Zuul簡介

Zuul的主要功能是路由和過濾器。路由功能是微服務的一部分,比如/api/user對映到user服務,/api/shop對映到shop服務。zuul實現了負載均衡。

zuul有以下功能:

  • Authentication
  • Insights
  • Stress Testing
  • Canary Testing
  • Dynamic Routing
  • Service Migration
  • Load Shedding
  • Security
  • Static Response handling
  • Active/Active traffic management

二、準備工作

繼續使用上一節的工程。在原有的工程上,建立一個新的工程。

三、建立service-zuul工程

其pom.xml檔案如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.forezp</groupId>
    <artifactId>service-zuul</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>service-zuul</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.2.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>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.RC1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>


</project>複製程式碼

在其入口applicaton類加上註解@EnableZuulProxy,開啟zuul:

@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ServiceZuulApplication {

    public static void main(String[] args) {
        SpringApplication.run(ServiceZuulApplication.class, args);
    }
}複製程式碼

加上配置檔案:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8769
spring:
  application:
    name: service-zuul
zuul:
  routes:
    api-a:
      path: /api-a/**
      serviceId: service-ribbon
    api-b:
      path: /api-b/**
      serviceId: service-feign複製程式碼

首先向eureka註冊自己,埠為8769,服務名為service-zuul;以/api-a/ 開頭的請求都指向service-ribbon;以/api-b/開頭的請求都指向service-feign;

依次執行這五個工程;開啟瀏覽器訪問:http://localhost:8769/api-a/hi?name=forezp ;瀏覽器顯示:

hi forezp,i am from port:8762

開啟瀏覽器訪問:http://localhost:8769/api-b/hi?name=forezp ;瀏覽器顯示:

hi forezp,i am from port:8762

這說明zuul起到了路由的作用;

四、服務過濾

zuul不僅只是路由,並且還能過濾,做一些安全驗證。繼續改造工程;

@Component
public class MyFilter extends ZuulFilter{

    private static Logger log = LoggerFactory.getLogger(MyFilter.class);
    @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();
        log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));
        Object accessToken = request.getParameter("token");
        if(accessToken == null) {
            log.warn("token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("token is empty");
            }catch (Exception e){}

            return null;
        }
        log.info("ok");
        return null;
    }
}複製程式碼
  • filterType:返回一個字串代表過濾器的型別,在zuul中定義了四種不同生命週期的過濾器型別,具體如下:
    • pre:路由之前
    • routing:路由之時
    • post: 路由之後
    • error:傳送錯誤呼叫
      • filterOrder:過濾的順序
      • shouldFilter:這裡可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
      • run:過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有許可權訪問。

這時訪問:http://localhost:8769/api-a/hi?name=forezp ;網頁顯示:

token is empty

訪問 http://localhost:8769/api-a/hi?name=forezp&token=22
網頁顯示:

hi forezp,i am from port:8762

本文原始碼下載:
github.com/forezp/Spri…

五、參考資料:

router_and_filter_zuul

優秀文章推薦:

相關文章