1. 程式人生 > >分散式專案(九)zuul 第一代閘道器

分散式專案(九)zuul 第一代閘道器

書接上回,這個接的有點久(手動滑稽)。。。

上次說道使用Nginx對coap接入做負載均衡,讓協議伺服器可以橫向擴充套件,但我們的裝置管理系統在訪問時還是訪問的我們伺服器的地址,如果現在有其它服務要呼叫我們的裝置管理系統如果直接使用其ip地址會有服務地址暴露的風險,並且後期如果做鑑權,都不好做,所以這裡我們引出了spring cloud另外一個元件,zuul閘道器。

Zuul是什麼

zuul是netfilx開源的一個api gateway伺服器,記住是api 伺服器,它只能做api請求閘道器,或者說是http請求的閘道器。像上面我們用Nginx做udp路由,使用的是埠監聽,它是做不了的。

為啥要用zuul 它能幹啥

為啥要用zuul,因為統一入口呀,統一入口能幹啥,那可就多了哦

  • 審查與監控
  • 動態路由,負載均衡
  • 靜態響應處理
  • 驗證與安全保障

為啥它能幹這麼多事呢?

上面說zuul是一個api伺服器,它本質上是一個web servlet伺服器,或者說是個filter應用,專幹攔截過濾的勾當((^o^)/~)。

zuul核心原理

zuul的工作流程是一系列的filters,和servlet的filter,spring中的aop是一樣一樣兒的。

一個http請求要走的路

http請求->zuul servlet->zuulFilter Runner -> filter1->filter2->.... ->業務伺服器-> filter2->filter1->http response

這有點向什麼,Status2的攔截器,也是請求的時候一個關卡一個關卡的過去,回來的時候在從後面的關卡一個一個的回來。

知道工作流程,突然發現一個問題,filter之間是如何傳遞資料的,一般這種問題就兩種解決方案,一是我自己走哪兒帶哪兒,這個好理解,就想我們帶錢一樣,就揣我兜裡,想用的時候就用,二是放在一個地方我用的時候在去拿,這就比如錢太多了拿不動,咋辦,放銀行,用的時候我再去取。

zuul採用的是第二種方式,filter之前通過一個requestContext的靜態類對進行資料的傳遞,那我把資料放進去了我取得時候咋知道是我的呢,錢存銀行,銀行會給你發張卡,你憑卡取錢,requestContext可沒有卡,但它有另一個東西,ThreadLocal執行緒資料快取器,這資料是A執行緒存的,那只有你A執行緒才能取出來,其它執行緒只能瞅著,錯,連瞅都瞅不了。

剛才我們說閘道器是一個服務的入口,或者說是一個服務叢集的入口,它的核心是filter,但我們又時候需要加一些新的filter,來滿足我們新的需求,但是我們又不能把閘道器給停的,閘道器停了不整個服務就乾瞪眼了麼,所以我們需要它能動態地載入filter。

zuul的過濾器是由groovy寫成的,這些過濾器被放在了zull server上特定的目錄下面,zuul會定期輪訓這些目錄,修改過的過濾器會動態地載入到zuul server中以便過濾請求使用。這就滿足了我們動態增過濾器的需求。

zuul過濾器型別

  • zuul定義了四種過濾器型別,這些過濾器型別對應請求的處於什麼週期
  • pre:請求路由之間呼叫,可以做許可權檢測
  • routing:這種過濾器將請求,這種過濾器用於構建傳送到微服務的請求,並使用Apache httpClient或ribbon請求微服務
  • post:這種過濾器在路由到微服務以後執行,可以用來新增標準的http header,收集統計資訊和指標,將響應從微服務傳送給客戶端
  • error:在其它階段發生錯誤是執行

這就有點想aop的請求前,請求後,發生錯誤執行了。

zuul還內建了兩個特殊的過濾器

staticResponseFilter:允許從zull本身生成響應,而不是將請求轉發,閘道器不是做轉發麼,它自己響應請求是個什麼鬼,看名字靜態?是噻,像那種百年不變的js,css,圖片這種靜態資源完全可以由閘道器自己響應。

surgicalDebugFilter:允許將特定請求路由到分隔的除錯叢集和主機上

關於zuul就簡單介紹一下,下面開始編寫程式碼。

建立protocol-zuul

maven配置

<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
	<version>2.1.1.RELEASE</version>
</dependency>

<dependency>
	<groupId>cn.le</groupId>
	<artifactId>consul-discovery-client</artifactId>
	<version>0.0.1-SNAPSHOT</version>
</dependency>

#application配置

spring.application.name=protocol-zuul
server.port=8888

#健康檢查路徑
spring.cloud.consul.discovery.health-check-path=/actuator/health

#eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka/

spring.cloud.consul.discovery.prefer-ip-address=true
spring.cloud.consul.discovery.instance-id=${spring.application.name}:${server.port}
spring.cloud.consul.discovery.hostname=${spring.application.name}
spring.cloud.consul.discovery.service-name=${spring.application.name}

#配置路由到此伺服器
zuul.routes.api-a.service-id=iot-manage
#配置路由規則
zuul.routes.api-a.path=/manage/**
zuul.routes.api-a.stripPrefix=false

zuul關於路由對映的方式兩種一種是使用ip對映,一種是現在使用的這種zuul.routes.api-a.service-id的方法,ip對映的方式可以在獨立使用zuul的時候使用,我們這裡使用了註冊中心,所以使用id名稱對映的方式,這種方式對動態擴容,服務發現、註冊友好。

啟動zuul服務

zuul啟動後,在consul的管理頁面就可以看到zuul的服務了。

前面我們直接訪問一下http://127.0.0.1:8081/manage/swagger-ui.html 可以正常開啟裝置管理系統的swagger的介面,但是現在我們有的服務閘道器,需要從服務閘道器去訪問, http://127.0.0.1:8888/manage/swagger-ui.html 8888是zuul服務的埠,利用訪問zuul的方式去訪問裝置管理系統看看能不能成功開啟swagger。

一樣能正常開啟,這就表示zuul成功了。

自定義過濾器

剛才我們只用利用zuul去訪問manager系統,但是沒做任何處理,如果我們需要在訪問之前對請求做處理,比如驗證是否登入。

建立AuthFilter類,並繼承ZuulFilter,宣告AuthFilter是一個ZuulFilter,並且可以讓ZuulFilter Runner呼叫。

package cn.le.pre;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

[@Component](https://my.oschina.net/u/3907912)
/**
 * 自定義過濾器,繼承zuulFilter即可
 */
public class AuthFilter extends ZuulFilter {

    //pre型別,請求路由之前呼叫
    [@Override](https://my.oschina.net/u/1162528)
    public String filterType() {
        return "pre";
    }
    //過濾器的執行順序,數字越小表示越先執行
    [@Override](https://my.oschina.net/u/1162528)
    public int filterOrder() {
        return 0;
    }
    //判斷此過濾器是否執行,true執行,false不執行
    [@Override](https://my.oschina.net/u/1162528)
    public boolean shouldFilter() {
        return true;
    }
    //過濾器執行邏輯
    [@Override](https://my.oschina.net/u/1162528)
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        System.out.println("AuthFilter----"+request);
        return null;
    }
}

這裡只打印了請求資訊,並沒有寫關於登入的邏輯,因為登入是一個綜合元件配套的邏輯,這裡篇幅有限就不實現了。

重新訪問一下http://192.168.0.105:8888/manage/swagger-ui.html

從控制日誌我們可以看出對請求進行的過濾。

結束語

https://gitee.com/distant/cloud-work.git

https://gitee.com/d