1. 程式人生 > >Spring Cloud Zuul(API閘道器服務)(2)

Spring Cloud Zuul(API閘道器服務)(2)

路由詳情

傳統路由配置

傳統路由配置方式就是在不依賴與服務發現機制的情況下,通過在配置檔案中具體指定每個路由表示式與服務例項的對映關係來實現API閘道器對外部請求的路由。

單例項配置:通過zuul.routes.<route>.path與zuul.routes.<route>.url引數對的方式進行配置進行配置,比如:

zuul.routes.api-a-url.path=/api-a-url/**
zuul.routes.api-a-url.url=http://localhost:8082/

該配置實現了對符合/api-a-url/**規則的請求路徑轉發到http://localhost:8082/地址的路由規則。比如

多例項配置:通過zuul.routes.<route>.path與zuul.routes.<route>.serviceId引數對的方式進行配置,比如:

zuul.routes.user-service.path=/user-service/**
zuul.routes.user-service.serviceId=user-service
ribbon.eureka.enabled=false
user-service.ribbon.listOfServers=http://localhost:8082/,http://localhost:8084/

該配置實現了對符合/user-service/**規則的請求路徑轉發到

http://localhost:8082http://localhost:8084兩個例項地址的路由規則。由於存在多個例項,API閘道器在進行路由轉發是需要實現負載均衡策略,於是需要Spring Cloud Ribbon的配合。

ribbon.eureka.enabled:由於zuul.routes.<route>.serviceId指定的服務名稱,預設情況下Ribbon會根據服務發現機制來獲取服務配置服務名對應的例項清單。但是這裡沒有整合Eureka之類的服務治理框架,所以要將引數設定為false,否則serviceId獲取不到對應的例項的清單。

user-service.ribbon.listOfServers:該引數與zuul.routes.<route>.serviceId的配置相對應,開頭的user-service對應了serviceId的值,這兩個引數的配置相當於在該應用內部手工維護了服務與例項的對應關係。

不論是單例項還是多例項的配置方式,都需要為每一對對映關係指定一個名稱,也就是<route>,每一個<route>對應了一條路由規則。每條路由規則都需要path屬性來定義個用來匹配客戶端請求的路徑表示式,並通過url或serviceId屬性來指定請求表示式對映具體例項地址或服務名。

服務路由配置

通過服務路由配置只需要通過zuul.routes.<route>.path與zuul.routes.<route>.serviceId引數對的方式進行配置即可。

zuul.routes.user-service.path=/user-service/**
zuul.routes.user-service.serviceId=user-service

除此之外還有一種方式配置更簡潔:zuul.routes.<serviceId>=<path>,其中<serviceId>用來指定路由的具體服務名,<path>用來配置匹配的請求的表示式。

zuul.routes.user-service=/user-service/**

因為預設情況下所有Eureka上的服務都被Zuul自動的建立對映關係來進行路由,這會使一些不開放的服務可能會被外部訪問到。這時候我們可以使用zuul.ignored-services引數來設定一個服務名匹配表示式來定義不自動建立路由的規則。如果服務名匹配表示式那麼zuul將跳過該服務不為其建立路由規則。比如:zuul.ignored-services=*的時候,zuul將對所有的服務都不自動建立路由規則。

預設情況下Zuul自動為服務建立的路由表示式會採用服務名作為字首,比如user-service他會產生/user-service表示式來對映,但是這樣的表示式規則比較單一,不利於管理。如果想通過-來分隔服務名與版本標示的話,只需要增加如下Bean即可:

    @Bean
    public PatternServiceRouteMapper serviceRouteMapper(){
        return new PatternServiceRouteMapper("(?<name>^.+)-(?<version>v.+$)","${version}/${name}");
    }

路徑匹配

Zuul中,路由匹配的路徑表示式採用Ant風格定義。Ant風格的路徑表示式使用起來非常簡單,它一共有三種萬用字元。

萬用字元 說明
匹配任意單個字元
* 匹配任意數量的字元
** 匹配任意數量的字元,支援多級目錄
   

參考

URL路徑 說明
/user-service/? 它可以匹配/user-service之後拼接一個任務字元路徑,比如/user-service/a
/user-service/* 它可以匹配/user-service之後拼接任何任務字元路徑,比如/user-service/a,/user-service/bb,但不能匹配/user-service/a/b
/user-service/** 它可以匹配/user-service之後拼接任何任務字元路徑,還可以匹配多級目錄/user-service/a/b

需要注意的是properties的配置無法保證有效,所以為了保證路由的優先順序,我們需要使用yaml檔案來配置。如:

zuul:
    routes:
        user-service-ext:
            path:/user-service/ext/**
            serviceId:user-service-ext
        user-service:
            path:/user-service/**
            serviceId:user-service

忽略表示式

通過zuul.ignored-patterns,該引數可以用來設定不希望被API閘道器進行路由的URL表示式。我們可以這麼設定:

zuul.ignored-patterns=/**/hello/**
zuul.routes.api-a.path=/api-a/**
zuul.routes.api-a.serviceId=hello-service

可以看到被攔截了。

路由字首

為了方便全域性的為路由規則增加字首資訊,Zuul提供了zuul.prefix引數來進行設定。

zuul.prefix=/zzf

本地跳轉

在Zuul實現的API閘道器路由功能中,還支援forward形式的服務端跳轉配置。

zuul.routes.api-bb.path=/api-bb/**
zuul.routes.api-bb.url=forward:/hello

然後在API閘道器上需要增加一個/hello/local的介面

@RestController
public class HelloController {

    @RequestMapping("/hello/local")
    public String hello(){
        return "Hello";
    }
}

Cookie與頭資訊

預設情況下,Spring Cloud Zuul在請求路由時,會過濾掉HTTP請求頭資訊中的一些敏感資訊,防止它們被傳遞到下游的外部伺服器。預設的敏感頭資訊通過zuul.sensitiveHeaders引數定義,包括Cookie、Set-Cookie、Authorization三個屬性。所以這會使Cookie在Zuul閘道器中預設不會傳遞,解決方法如:

1.通過設定全域性引數為空來覆蓋預設值,如:

zuul.sensitiveHeaders=

雖然可以實現Cookie的傳遞,但是破壞了預設設定的泳衣。

2.通過指定路由的引數來配置,方法有兩種:

#方法一:對指定路由開啟自定義敏感頭
zuul.routes.<router>.customSensitiveHeaders=true
#方法二:對指定路由的敏感頭設定為空
zuul.routes.<router>.sensitiveHeaders=

重定向問題

通過重定向的方式跳轉到登入後的頁面,此時登入後的請求結果狀態碼為302,請求響應頭資訊的Location指向了具體的服務例項,而請求頭資訊中的Host也指向了具體的服務例項IP地址和埠。

解決方式是:

zuul.addHostHeader=true

該引數配置,能夠使得閘道器在進行路由轉發前為請求設定Host頭資訊,以標示最初的服務端請求地址。

Hystrix 和 Ribbon支援

Zuul天生擁有執行緒隔離和斷路器的自我保護功能,以及對服務呼叫的客戶端負載均衡功能。但是當使用path與url的對映關係來配置路由規則時,對於路由轉發的請求不會採用HystrixCommand來包裝,所以這類路由請求沒有執行緒隔離和斷路器的保護,並且也不會有負載均衡的能力。所以在使用Zuul的時候儘量使用path和serviceId的組合來進行配置。

在使用Zuul搭建API閘道器的時候,可以通過Hystrix和Ribbon的引數來調整路由請求的各種超時時間等配置,比如:

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:該引數可以用來設定API閘道器中路由轉發請求的HystrixCommand執行超時時間,單位為毫秒。當路由轉發請求的命令執行時間超過該配置之後,Hystrix會將該執行命令標記為TIMEOUT並丟擲異常。

ribbon.ConnectTimeout:該引數來設定路由轉發請求的時候,建立請求連線的超時時間。

ribbon.ReadTimeout:該引數用來設定路由轉發請求的超時時間。

如果想要關閉請求重試機制可以通過下面兩個引數設定:

zuul.retryable=false
zuul.routes.<route>.retryable=false

zuul.retryable用來全域性關閉重試機制。而zuul.routes.<route>.retryable=false則是指定路由關閉重試機制。

參考《Spring Cloud微服務實戰》