天天看點

SpringCloud學習筆記(六):使用Zuul實作路由和請求過濾Zuul的作用實作

SpringCloud學習筆記(六):使用Zuul實作路由和請求過濾

  • Zuul的作用
    • 沒有使用Zuul時的情況
    • 使用了Zuul時的情況
  • 實作
    • 路由實作
    • 過濾器實作

Zuul的作用

沒有使用Zuul時的情況

SpringCloud學習筆記(六):使用Zuul實作路由和請求過濾Zuul的作用實作

通過先前的内容我們可以很容易實作如上圖所示的架構。在正常的項目中,調用服務前基本都需要經過鑒權之類的操作。使用上面的架構,每個開放服務都需要實作鑒權,不僅提高了開發的複雜程度,而且使得代碼變得備援。是以我們需要一個元件來搭建開放服務和使用者端之間的橋梁,在這一層面上實作代理、鑒權等操作。Netfilx Zuul就能達成這一目的。

使用了Zuul時的情況

SpringCloud學習筆記(六):使用Zuul實作路由和請求過濾Zuul的作用實作

在原有架構中加入Zuul元件後,架構如上圖所示,使用了Zuul之後,使用者調用我們系統服務的請求将會先到達Zuul網關,再由網關對不同的請求進行路由轉發。在執行轉發操作之前,Zuul可以通過過濾器執行一系列代碼,實作請求過濾,達到類似Spring MVC中攔截器的效果。此時各個微服務的開發人員不需要在關注諸如鑒權之類的問題,鑒權由Zuul統一處理,隻有鑒權通過的請求才會被路由,否則Zuul直接過濾掉該請求。

實作

路由實作

我們在項目中建立一個Maven子產品,我這裡給子產品命名為zuulgateway,在子產品下pom.xml中新增如下的依賴

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <!-- 導入Spring Cloud的依賴管理 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>

        <!--整合eureka用戶端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>

        <!--整合zuul網關-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
            <version>2.0.3.RELEASE</version>
        </dependency>
        
    </dependencies>

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

然後在resource目錄下建立application.yml,配置一下Zuul的路由轉發規則。application.yml内容如下

server:
  port: 8070 #端口号
spring:
  application:
    name: app-zuul-gateway #應用名

##配置eureka,從注冊中心擷取服務位址
eureka:
  client:
    service-url:
           defaultZone: http://localhost:9090/eureka/
###因為該應用為服務提供者,是eureka的一個用戶端,需要注冊到注冊中心
    register-with-eureka: true
###是否需要從eureka上檢索服務
    fetch-registry: true
  instance:
        prefer-ip-address: true #将自己的ip位址注冊到Eureka服務中
        ip-address: 127.0.0.1
        instance-id: ${spring.application.name}###${server.port} #指定執行個體ID



##zuul路由規則
zuul:
  host:
    connect-timeout-millis: 15000 #HTTP連接配接逾時大于Hystrix的逾時時間
    socket-timeout-millis: 60000   #socket逾時
  routes:
    cargo-service: #這是個随便取的名字,用于識别不同的路由,從原位址到目的位址
      path: /cargo-service/** #通路的位址
      serviceid: app-cargo #轉發到哪個微服務

    cargolist-service:
      path: /cargolist-service/**
      serviceid: app-cargolist

ribbon:        #設定ribbon的逾時時間小于zuul的逾時時間
  ReadTimeout: 10000
  ConnectTimeout: 10000
           

這裡注意一下,一定要讓Zuul的逾時時間大于Ribbon的逾時時間,否則Zuul無法正常工作,請求會失敗。

然後在src/main/java下建立一個runner包,在包下建立啟動類,類上添加@EnableZuulProxy注解,表示啟動Zuul,啟動微服務即可測試檢視效果。啟動類完整代碼如下

package runner;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy//啟用Zuul
public class ZuulGatewayApp {
    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApp.class, args);
    }
}
           

微服務啟動完成後,通路http://localhost:8070/cargolist-service/cargoList/123,通過Zuul微服務來調用app-cargo-list微服務,頁面正常傳回結果,Zuul在此時已經起到了路由代理的作用,Zuul的基本配置就完成了。

過濾器實作

Zuul的過濾器實作同樣非常簡單,隻需要建立一個過濾器類,并且讓SpringBoot架構掃描到它就可以實作了,我們在子產品下再建立一個filter包用來存放過濾器類,建立一個TokenZuulFilter類,并繼承ZuulFilter。ZuulFilter是一個抽象方法,裡面定義了一系列攔截器執行過程。TokenZuulFilter類完整代碼如下。

package filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.apache.commons.lang.StringUtils;

import javax.servlet.http.HttpServletRequest;

@Component
public class TokenZuulFilter extends ZuulFilter {
    @Override
    public String filterType() {
        //pre:請求被路由前執行
        //routing:路由請求調用時執行
        //post:路由完成或路由送出後出錯後傳回前執行
        //error:處理請求時發生錯誤執行
        return "pre";
    }

    @Override
    public int filterOrder() {
        //數字越小優先級越高
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        //true執行,false不執行
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getParameter("token");
        if(StringUtils.isEmpty(token)||!"123".equals(token)){//檢查token
            requestContext.setSendZuulResponse(false); // 過濾該請求,不對其進行路由
            requestContext.setResponseStatusCode(401); // 設定響應狀态碼
            requestContext.setResponseBody("TOKEN ERROR"); // 設定響應狀态碼
            return null;
        }
        return null;
    }
}

           

在啟動類@SpringBootApplication注解加入包掃描的參數,添加filter包,重新開機微服務即可測試檢視結果。

通路http://localhost:8070/cargolist-service/cargoList/123,發現頁面傳回TOKEN ERROR,F12檢視請求狀态碼為401。我們在URL上加入參數再通路http://localhost:8070/cargolist-service/cargoList/123?token=123,此時發現頁面可以正常傳回,至此Zuul過濾器實作就完成了。

繼續閱讀