SpringCloud微服務就是把一個大的項目拆分紅多個小的模塊,而後模塊之間經過遠程調用、服務治理的技術互相配合工做,隨着業務的增長,項目也將會愈來愈龐大,接口數量也隨之增長,對外提供服務的接口也會增長,運維人員對於這些接口的管理也會變得愈來愈難。另外一方面對於一個系統來講,權限管理也是一個不可少的模塊,在微服務架構中,系統被拆分,不可能每一個模塊都去添加一個個權限管理,這樣系統代碼重複、工做量大、後期維護也難。爲了解決這些常見的架構問題,API網關應運而生。SpringCloudZuul是基於Netflix Zuul實現的API網關組件,它實現了請求路由、負載均衡、校驗過濾、與服務治理框架的結合、請求轉發是的熔斷機制和服務的聚合等功能。
<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>
@EnableZuulProxy
註解開啓API網關服務功能@SpringBootApplication @EnableZuulProxy public class ApigatewayApplication { public static void main(String[] args) { SpringApplication.run(ApigatewayApplication.class, args); } }
spring: application: name: api-gateway server: port: 8500 zuul: routes: # 面向服務的路由 api-a: path: /api-a/** serviceId: FEIGN-CONSUMER # 傳統的路由 api-b-url: path: /api-b-url/** url: http://localhost:30000/ eureka: client: service-url: defaultZone: http://localhost:8888/eureka/
這裏的代碼是接着前面的,啓動eureka-server、user-server、feign-consumer、article-server和api-gateway。我沒添加了eureka的依賴,因此api-gateway也是服務提供方在註冊中心註冊:
而後訪問http://localhost:8500/api-a/feign_consumer/find
和http://localhost:8500/api-b-url/a/u/1
java
在上面的配置文件文件中,使用兩種路由規則的配置方法,一種是面向服務的,一種是使用傳統的url。全部符合/api-a/**
的請求都將轉發到feign-consumer,一樣全部符合/api-b-url/**
的請求都將轉發到http://localhost:30000/
,也就是前面使用的article-service。兩種規則的配置很明顯:面向服務的使用serviceId配置服務實例,而傳統的直接使用服務的地址。git
前面也提到網關能夠處理微服務的權限問題,在單體架構的時候咱們一般會使用攔截器或過濾器對請求進行權限的校驗,一樣在SpringCloudZuul中也提供了過濾器來進行請求的過濾與攔截,實現方法只要咱們繼承抽象類ZuulFilter
並實現它定義的4個抽象方法。下面定義個攔截器來檢查HttpServletRequest中是否帶有accessToken參數程序員
AccessFilter
@Component public class AccessFilter extends ZuulFilter{ private static final Logger logger = LoggerFactory.getLogger(AccessFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); logger.info("send{} request to {}",request.getMethod(),request.getRequestURI().toCharArray()); String accessToken = request.getParameter("accessToken"); if(StringUtils.isBlank(accessToken)){ logger.warn("accessToken is empty"); currentContext.setSendZuulResponse(false); currentContext.setResponseStatusCode(401); return null; } logger.info("accessToken {}" ,accessToken); return null; } }
上面說到咱們須要實現抽象類的ZuulFilter的四個抽象方法;spring
- filterType:過濾器類型,他決定過濾器在請求的哪一個生命週期執行。在Zuul中有四種不一樣的生命週期過濾器:
- pre:能夠在請求被路由以前調用; - routing:在路由請求是調用; - post:在routing和error過濾器以後被調用; - error:處理請求是發生錯誤是被調用
- filterOrder:過濾器的執行順序,數值越小優先級越高
- shouldFilter:判斷過濾器是否須要執行
- run: 過濾器的具體邏輯。上面的run方法中判斷請求是否帶有accessToken參數,若是沒有則是非法請求,使用
currentContext.setSendZuulResponse(false);
表示該請求不進行路由。而後設置響應碼。
請求的生命週期具體詳解能夠參考《SpringCloud微服務實戰》api
在上面的配置中使用了zuul.toutes.<route>.path
和zuul.toutes.<route>.url
參數的方式配置單實例的路由,而在微服務架構中,爲了服務的高可用,通常會將一個服務部署多個。傳統的多實例的路由配置,Zuul提供瞭如下方法:架構
經過zuul.toutes.<route>.path
與zuul.toutes.<route>.serviceId
配置,以下:
zuul.routes.feign-consumer.path=/feign/**
zuul.routes.feign-consumer.serviceId=feign-consumer
robbin.eureka.enable=false
feign-consumer.ribbon.listOfServers=http://localhost:50000/,http://localhost:50001/
該配置實現了對符合/feign/**
規則的請求轉發到http://localhost:50000/,http://localhost:50001/
兩個實例地址的路由規則。這裏的serviceId是有程序員手動命名的服務名稱。robbin.eureka.enable=false
設置Ribbon不根據服務發現機制來獲取配置服務對應的實例清單。app
zuul: routes: api-a: path: /api-a/** serviceId: feign-consumer
該配置實現了對符合/api-a/**
規則的請求路徑轉發到名爲feign-consumer
的服務實例上去的路由規則。 api-a
是任意的路由名稱。還可使用一種更加簡潔的方法zuul.routes.<serviceId>=<path>
,這裏serviceId指定具體的服務名,path配置匹配的請求表達式。負載均衡
通配符 | 含義 | url | 說明 |
---|---|---|---|
? | 匹配任意單個字符 | /feign/? | 匹配/feign/以後拼接一個任意字符的路徑,如/feign/a |
* | 匹配任意數量的字符 | /feign/* | 匹配/feign/以後拼接任意字符的路徑,如/feign/aaa |
** | 匹配任意數量的字符,支持多級目錄 | /feign/** | 能夠匹配/feign/*包含的內容以外,還可匹配形如/feign/a/b的多級目錄 |
zuul.ignored-services=hello-service:
忽略掉一個服務;zuul.ignored-patterns=/**/feign/**:
忽略/feign接口路由;zuul.prefix:
爲路由添加統一前綴;zuul.add-host-header: true:
在請求路由轉發前爲請求設置Host頭信息;zuul.sensitiveHeaders=
:設置全局參數爲空來覆蓋默認敏感頭信息zuul.routes.<route>.customSensitiveHeaders=true
:對指定路由開啓自定義敏感頭zuul.routes.<route>.sentiviteHeaders=
:將指定路由的敏感頭設置爲空。zuul.retryable=false
:關閉重試機制zuul.routes.<route>.retryable=false
:指定路由關閉重試機制zuul.<SimpleClassName>.<fileterType>.disable=true
:禁用指定的過濾器,<SimpleClassName>
表明過濾器的類名,<fileterType>
表明過濾器的類型。在Zuul中Hystrix和Ribbon的配置與傳統的Hystrix和Ribbon服務的配置同樣。框架
參考:《SpringCloud微服務實戰》運維