SpringCloud系列八:Zuul 路由訪問(Zuul 的基本使用、Zuul 路由功能、zuul 過濾訪問、Zuul 服務降級)
1、概念:Zuul 路由訪問
2、具體內容
在現在為止所有的微服務都是通過 Eureka 找到的,但是在很多的開發之中為了規範微服務的使用,提供有一個路由的處理控制組件:Zuul,也就是說 Zuul 就作為中間的一個代理層出現。
2.1、Zuul 的基本使用
本次使用 Zuul 將訪問無安全認證的微服務信息,例如:公司信息就屬於無安全認證的微服務;
1、 為了突出 zuul 的功能,建立一個新的主機映射:
127.0.0.1 gateway-9501.com
以後所有的微服務的訪問不再直接進行處理了,而是通過 Zuul 進行跳轉後獲得
2、 建立一個新的模塊:microcloud-zuul-gateway-9501;
3、 【microcloud-zuul-gateway-9501】修改 pom.xml 文件,追加 zuul 相關依賴包:
· 註意:Zuul 服務最終還是會註冊到 Eureka 之中,那麽千萬要將其配置好;
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency><dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
4、 【microcloud-zuul-gateway-9501】修改 application.yml 配置文件:
server: port: 9501 eureka: client: # 客戶端進行Eureka註冊的配置 service-url: defaultZone: http://edmin:[email protected]:7001/eureka,http://edmin:[email protected]:7002/eureka,http://edmin:[email protected]:7003/eureka instance: lease-renewal-interval-in-seconds: 2 # 設置心跳的時間間隔(默認是30秒) lease-expiration-duration-in-seconds: 5 # 如果現在超過了5秒的間隔(默認是90秒) instance-id: gateway-9501.com # 在信息列表時顯示主機名稱 prefer-ip-address: true # 訪問的路徑變為IP地址 info: app.name: study-microcloud company.name: www.study.cn build.artifactId: $project.artifactId$ build.version: $project.verson$ spring: application: name: microcloud-zuul-gateway
5、 【microcloud-zuul-gateway-9501】創建程序啟動的主類:
package cn.study.microcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableZuulProxy public class Zuul_9501_StartSpringCloudApplication { public static void main(String[] args) { SpringApplication.run(Zuul_9501_StartSpringCloudApplication.class, args); } }
可以看到【microcloud-zuul-gateway-9501】已經註冊到eureka中了
6、 訪問公司微服務信息:
· 原始訪問路徑:http://company-8101.com:8101/company/get/hello;
· Zuul 代理訪問:http://gateway-9501.com:9501/microcloud-provider-company/company/get/hello;
現在使用 Zuul 代理的只有 company,因為 dept 上有安全認證不能訪問。
2.2、Zuul 路由功能
整體的 Zuul 運行之後你會發現,zuul 所實現就是一個代理功能,那麽現在就會出現一個問題,例如:以之前訪問的路徑為例:
http://gateway-9501.com:9501/microcloud-provider-company/company/get/hello
此時必須要知道應用程序的名稱,但是如果不知道這個名稱肯定無法訪問,可是如果讓用戶知道這個名稱,那麽使用 zuul 就 沒有任何的實際意義,直接調用即可。而 zuul 的主要功能是代理,那麽代理的功能就是不讓用戶看見真實的操作,所以在實際的使用之中就需要為 zuul 設置一些路由規則。
1、 【microcloud-zuul-gateway-9501】為指定的應用設置路徑,修改 application.yml 配置文件:
zuul: routes: microcloud-provider-company: /company-proxy/**
那麽此時就可以通過“/company-proxy”來訪問“microcloud-provider-company”名稱。
http://gateway-9501.com:9501/company-proxy/company/get/hello
但是現在還會存在有一個實際的問題,雖然現在開啟了路由訪問支持,但是依然支持通過應用名稱進行訪問:
http://gateway-9501.com:9501/microcloud-provider-company/company/get/hello
2、 【microcloud-zuul-gateway-9501】修改 application.yml 配置文件忽略掉應用名稱訪問:
· 忽略掉“microcloud-provider-company”應用名稱;
zuul: ignored-services: microcloud-provider-company routes: microcloud-provider-company: /company-proxy/**
這個時候就可以進行代理的安全使用,但是如果你一個系統之中存在有幾百個微服務,如果按照如上的方式進行配置就會非 常的麻煩,所以最簡單的做法是可以采用一個通配符“*”的模式來完成:
zuul: ignored-services: "*" routes: microcloud-provider-company: /company-proxy/**
現在表示所有的 Eureka 中的服務名稱的信息訪問都要忽略掉,所有的訪問都需要配置一個映射路徑的模式來完成。
3、 【microcloud-zuul-gateway-9501】除了以上的模式進行服務定義之外,在 zuul 之中也可以采用如下的方式進行處理:
zuul: ignored-services: "*" routes: mycompany.path: /company-proxy/** mycompany.serviceId: microcloud-provider-company
其中在代碼裏面出現的“mycompany”是一個邏輯名稱,該名稱的主要作用是將 path 與 serviceId 綁定在一起。
4、 【microcloud-zuul-gateway-9501】如果說現在不想通過 Eureka 進行訪問,則也可以直接連接到 company 微服務的地址
zuul: ignored-services: "*" routes: company.path: /company-proxy/** company.url: http://company-8101.com:8101/company
此時的地址上由於已經存在有了“company”前綴,所以訪問地址為:
http://gateway-9501.com:9501/company-proxy/get/hello
但是從實際的開發來講不建議采用此類模式處理,因為所有的服務如果直接綁定了指定的服務提供者的地址,那麽將不方便 進行負載均衡的配置處理,而且沒有 Eureka 所有微服務的管理也非常不方便。
5、 【microcloud-zuul-gateway-9501】設置公共前綴:
zuul: prefix: /study-proxy ignored-services: "*" routes: microcloud-provider-company: /company-proxy/**
一旦存在有前綴定義之後所有微服務的訪問上就必須追加有前綴名稱:
http://gateway-9501.com:9501/study-proxy/company-proxy/company/get/hello
以上的地址:
· “/study-proxy”:整個 zuul 的前綴;
· “/company-proxy”:是在 zuul 中定義的映射路徑;
· “/company/get/hello”:是微服務提供者提供的操作路徑。
2.3、zuul 過濾訪問
對於 zuul 的功能本質上就屬於一個代理操作,但是在實際的使用之中,所有的微服務一定都要有自己的認證信息,那麽在這 樣的狀態下,如果你當前所代理的微服務具有認證信息,那麽就必須在其訪問前追加認證的頭部操作,這樣的功能就需要通過 zuul的過濾操作完成。
1、 【microcloud-zuul-gateway-9501】修改 application.yml 配置,這個配置之中追加 dept 微服務的代理;
zuul: prefix: /study-proxy ignored-services: "*" routes: microcloud-provider-company: /company-proxy/** microcloud-provider-dept: /dept-proxy/**
此時的訪問路徑:http://studyjava:[email protected]:9501/study-proxy/dept-proxy/dept/get/1;現在的密碼只是設置給了 zuul,而 zuul 並不能夠將認證的信息傳遞到部門微服務之中。
2、 【microcloud-zuul-gateway-9501】追加過濾處理操作:
package cn.study.microcloud.filter; import java.nio.charset.Charset; import java.util.Base64; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; public class AuthorizedRequestFilter extends ZuulFilter { // 進行授權訪問處理 @Override public Object run() { // 表示具體的過濾執行操作 RequestContext currentContext = RequestContext.getCurrentContext() ; // 獲取當前請求的上下文 String auth = "studyjava:hello"; // 認證的原始信息 byte[] encodedAuth = Base64.getEncoder() .encode(auth.getBytes(Charset.forName("US-ASCII"))); // 進行一個加密的處理 // 在進行授權的頭信息內容配置的時候加密的信息一定要與“Basic”之間有一個空格 String authHeader = "Basic " + new String(encodedAuth); currentContext.addZuulRequestHeader("Authorization", authHeader); return null; } @Override public boolean shouldFilter() { // 該Filter是否要執行 return true ; } @Override public int filterOrder() { return 0; // 設置優先級,數字越大優先級越低 } @Override public String filterType() { // 在進行Zuul過濾的時候可以設置其過濾執行的位置,那麽此時有如下幾種類型: // 1、pre:在請求發出之前執行過濾,如果要進行訪問,肯定在請求前設置頭信息 // 2、route:在進行路由請求的時候被調用; // 3、post:在路由之後發送請求信息的時候被調用; // 4、error:出現錯誤之後進行調用 return "pre"; } }
3、 【microcloud-zuul-gateway-9501】建立一個配置程序類作為認證請求的配置 Bean。
package cn.study.microcloud.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import cn.study.microcloud.filter.AuthorizedRequestFilter; @Configuration public class ZuulConfig { @Bean public AuthorizedRequestFilter getAuthorizedRequestFilter() { return new AuthorizedRequestFilter() ; } }
那麽這個時候就意味著你現在的程序可以直接利用 zuul 的代理訪問所有加密的微服務。
4、 【microcloud-zuul-gateway-9501】考慮到 zuul 也需要進行安全訪問,所以應該修改項目中的 pom.xml 配置文件,追加 Spring 安全訪 問配置處理操作:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
5、 【microcloud-zuul-gateway-9501】修改 application.yml 配置文件,最佳有用戶信息配置:
security:
basic:
enabled: true
user:
name: zdmin
password: studyjava
那麽此時現在表示 zuul 的代理上有了認證信息,則訪問的地址上必須加上 zuul 的認證操作:
http://zdmin:[email protected]:9501/study-proxy/dept-proxy/dept/get/1
6、 【microcloud-service】現在所有的服務要通過 zuul 的代理來進行操作對於代理的配置如果要通過 feign 進行訪問,那麽在編寫 feign 的時候就必須設置代理的服務名稱;
package cn.study.service; import java.util.List; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import cn.study.commons.config.FeignClientConfig; import cn.study.service.fallback.IDeptClientServiceFallbackFactory; import cn.study.vo.Dept; @FeignClient(value = "MICROCLOUD-ZUUL-GATEWAY", configuration = FeignClientConfig.class, fallbackFactory = IDeptClientServiceFallbackFactory.class) public interface IDeptClientService { @RequestMapping(method = RequestMethod.GET, value = "/study-proxy/dept-proxy/dept/get/{id}") public Dept get(@PathVariable("id") long id); @RequestMapping(method = RequestMethod.GET, value = "/study-proxy/dept-proxy/dept/list") public List<Dept> list(); @RequestMapping(method = RequestMethod.POST, value = "/study-proxy/dept-proxy/dept/add") public boolean add(Dept dept); }
7、 【microcloud-service】修改服務的配置類,測試訪問的應該是 zuul 的地址:
package cn.study.commons.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import feign.Logger; import feign.auth.BasicAuthRequestInterceptor; @Configuration public class FeignClientConfig { @Bean public Logger.Level getFeignLoggerLevel() { return feign.Logger.Level.FULL ; } @Bean public BasicAuthRequestInterceptor getBasicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("zdmin", "studyjava"); } }
8、 【microcloud-zuul-gateway-9501】默認情況下只要配置了過濾器,就可以進行一個正常的啟動,如果現在有些過濾器突然不想讓它 用了,則也可以通過修改 application.yml 配置文件讓其禁用:
zuul: AuthorizedRequestFilter: pre: disable: true
此時表示“AuthorizedRequestFilter”過濾器將被禁止使用。如果以後有多個過濾服務出現的話,可以通過配置文件實現過濾 的啟用與禁用控制。
2.4、Zuul 服務降級
Zuul 是一個代理服務,那麽如果被代理的服務突然斷掉了,那麽這個時候 zuul 上面一定會顯示出錯誤信息。例如:現在停止 掉“dept-8001:8001”端口上的微服務。
如果現在程序無法使用,則 zuul 的代理執行時就會出現有 timeout 的信息。但是千萬要記住,由於現在的客戶端已經提供有了 feign 中的服務降級的配置支持,所以客戶端沒有任何的問題,問題只出現在代理端。但是對於一個完善的 zuul 的代理應該更好的 實現服務降級的處理操作,所以如果有需要也可以在 zuul 中進行服務降級配置。
1、 【microcloud-zuul-gateway-9501】建立一個 Fallback 的回退處理類。
package cn.study.microcloud.fallback; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import org.springframework.cloud.netflix.zuul.filters.route.ZuulFallbackProvider; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.client.ClientHttpResponse; import org.springframework.stereotype.Component; @Component public class DeptProviderFallback implements ZuulFallbackProvider { @Override public String getRoute() { return "microcloud-provider-dept"; // 設置好處理的失敗路由 } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream( "{\"deptno\":777777,\"dname\":\"【ERROR】Zuul-Fallback\",\"loc\":\"Gateway客戶端提供\"}" .getBytes()); // 當出現服務調用錯誤之後返回的數據內容 } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders() ; headers.set("Content-Type", "text/html; charset=UTF-8"); return headers; } @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.BAD_REQUEST; } @Override public int getRawStatusCode() throws IOException { return HttpStatus.BAD_REQUEST.value(); } @Override public String getStatusText() throws IOException { return HttpStatus.BAD_REQUEST.getReasonPhrase(); } @Override public void close() { }}; } }
2、 【microcloud-zuul-gateway-9501】直接訪問地址:
http://zdmin:[email protected]:9501/study-proxy/dept-proxy/dept/get/1
由於此時你返回的都是錯誤的代碼,則客戶端接收到此代碼之後會認為服務器端已經死掉了。
SpringCloud系列八:Zuul 路由訪問(Zuul 的基本使用、Zuul 路由功能、zuul 過濾訪問、Zuul 服務降級)