SpringCloud動態路由--Zuul

博客同步至GitPress:https://gitpress.io/@yangshijie/spring_cloud_zuul

示例代碼已上傳Github: https://github.com/yshijie/spring_cloud_demo

Zuul組件簡介

Zuul組件主要是用來做動態路由轉發和請求攔截過濾等;

在客戶端訪問服務端時,經常會有一些通過驗證用戶的token或者請求頭之類的去判斷並且指定具體訪問哪些數據服務,例如不同組織機構的用戶通過請求的token的不同被服務端指定分發到不同的數據中心去查詢對應的數據;

以及在客戶端請求服務端時,服務端攔截客戶端請求,可以對請求做一些預處理等操作;

在SpringCloud工程中,創建了兩個數據服務datacenter-a和datacenter-b,以及一個註冊服務,一個分發服務,這個分發服務就是用來指定路由去訪問具體哪個數據中心的數據;

核心類

Zuul組件的核心類是ZuulFilter,通過自定義過濾類繼承該類,並重寫指定方法進行請求的攔截處理;

public class MyFilter extends ZuulFilter {

    Override
    public String filterType() {
        return "pre";
    }

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

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

    @Override
    public Object run() {
        return null;
    }
}

filterType方法:指定在什麼地方進行攔截,可以使是請求前/後,發生錯誤時等;

pre:在路由轉發之前作用;
routing:在路由時起作用;
post:在返回結果時作用;
error:在整個路由階段,出現異常時作用;

filterOder方法:攔截的優先級,0表示最大;

shouldFliter方法:是否攔截,可以通過一些邏輯判斷是否需要進行攔截;

run方法:執行具體的攔截操作;

添加依賴

在需要進行動態路由轉發的服務(即分發服務)的pom.xml文件中加入依賴:

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

動態路由轉發

通過請求地址不同將服務指向不同的子服務,例如,服務集羣中,A服務用於存儲用戶信息,B服務用於存儲相關的商品信息,在請求是通過路徑設定user/goods將查詢指向不同的服務;

配置轉發信息

啓動類註解

在需要進行動態路由轉發的服務(即分發服務)的啓動類上配置@EnableZuulProxy註解:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class DispatchServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DispatchServerApplication.class, args);
    }
}

application.yml文件配置

在分發服務的application.yml文件中配置需要轉發的邏輯和轉發的對應服務地址:

spring:
    application:
        name: dispatch-server
server:
    port: 8760
eureka:
    client:
        service-url:
            defaultZone: http://localhost:8761/eureka/
zuul:
    retryable: false
    routes:
        data-a:
            path: /user/**
            serviceId: data-server-a
        data-b:
            path: /goods/**
            serviceId: data-server-b

請求測試

通過網關訪問:

http://localhost:8760/alarm/aaa/getData
http://localhost:8760/goods/aaa/getData

此時根據上面yml中的配置,第一個請求將自動轉發到data-server-a這個數據服務,第二個請求將自動轉發到data-server-b這個數據服務;

請求攔截過濾

4中的方法是一個比較簡單直白的做法,也可以對請求進行攔截判斷,通過請求的不同參數、或者請求頭信息等,將客戶端請求指向不同的服務;

yml配置路由信息

zuul:
    routes:
        data-a:
            path: /**
            serviceId: service-datacenter-a
        data-b:
            path:/**
            serviceId:service-datacenter-b

過濾請求

@Value("${zuul.routes.data-a.serviceId}")
private String aa;

@Value("${zuul.routes.data-b.serviceId}")
private String bb;

@Override
public Object run() throws ZuulException {
    RequestContext ctx = RequestContext.getCurrentContext();
    HttpServletRequest request = ctx.getRequest();
    HttpServletResponse response = ctx.getResponse();

    String userType = request.getParameter("userType");
    String serviceId = null;
    try {
        if (userType != null) {
            if (userType.equals("A")) {
                serviceId = aa;
            } else if (userType.equals("B")) {
                serviceId = bb;
            }
        } else {
            serviceId = "xxx";
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (serviceId == null) {
        //服務查詢失敗 不再路由直接返回
        response.setHeader("Content-Type", "application/json;charset=UTF-8");
        ctx.setSendZuulResponse(false);
        ctx.setResponseBody("Error: No service");
    } else {
        //轉發請求
        log.info("--->>> Forward to service :" + serviceId);
        ctx.set("serviceId", serviceId);
    }
    return null;
}

在該類上添加@Configuration註解表明是個配置類;

以上做法中,訪問的地址爲同一個,但是根據傳入的參數不同,利用Zuul攔截請求,將請求重新定義定指定轉發到不同的子服務中;

請求測試

兩個子服務分別訪問地址爲:

A:http://localhost:8763/aaa/getData?userType=""
B:http://localhost:8762/aaa/getData?userType=""

通過網關訪問時,請求http://localhost:8760/aaa/getData?userType="",當參數傳入A時,請求轉發到A服務,當傳輸傳入B時,轉發到B服務;

這樣對用戶來說是無感覺的,可以將判斷標準定爲請求的token等來作爲轉發的判斷條件等;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章