<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency>
spring-cloud-starter-zuul包含zuul-core、spring-cloud-starter-hystrix、spring-cloud-starter-ribbon、spring-cloud-starter-actratorweb
//@SpringCloudApplication = @SpringBootApplication + @EnableDiscoveryClient + @EnableCircuitBreaker @EnableZuulProxy @SpringCloudApplication public class ApiGatewayApplication { public static void main(String[] args) { SpringApplication.run(ApiGatewayApplication.class, args); } }
spring.application.name=api-gateway server.port=5555
只須要加入spring
#實現傳統的路由轉發功能 zuul.routes.api-a-url.path=/api-a-url/** zuul.routes.api-a-url.url=http://localhost:8080/
全部符合/api-a-url/**規則的訪問都將被路由轉發到http://localhost:8080/地址上,也就是說當咱們訪問http://localhost:5555/api-a-url/hello的時候,
API網關服務會將該請求路由到http://localhost:8080/hello提供的微服務上api
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
spring.application.name=api-gateway server.port=5555 #實現傳統的路由轉發功能 #zuul.routes.api-a-url.path=/api-a-url/** #zuul.routes.api-a-url.url=http://localhost:8080/ zuul.routes.api-a.path=/api-a/** zuul.routes.api-a.serviceId=eureka-client zuul.routes.api-b.path=/api-b/** zuul.routes.api-b.serviceId=feign-consumer #eureka.instance.hostname=localhost #註冊服務的註冊中心地址 eureka.client.serviceUrl.defaultZone=http://localhost:1001/eureka/
注意與傳統路由的區別,一個是面向url的,一個是面向服務的服務器
微服務中不須要調用此業務服務進行鑑權校驗cookie
public class AccessFilter extends ZuulFilter { private static Logger log = LoggerFactory.getLogger(AccessFilter.class); //filterType:過濾器的類型,他決定過濾器會在請求的哪一個生命週期中執行,pre表明會在請求被路由以前執行 @Override public String filterType() { return "pre"; } //filterOrder過濾器執行順序 @Override public int filterOrder() { return 0; } //shouldFilter執行生效的條件 @Override public boolean shouldFilter() { return true; } //過濾器的具體邏輯 @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info("send {} request to {}", request.getMethod(), request.getRequestURL().toString()); Object accessToken = request.getParameter("accessToken"); if(null == accessToken) { log.warn("access token is empty."); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); return null; } log.info("access token ok."); return null; } }
@EnableZuulProxy @SpringCloudApplication public class ApiGatewayApplication { @Bean public AccessFilter accessFilter() { return new AccessFilter(); } public static void main(String[] args) { SpringApplication.run(ApiGatewayApplication.class, args); } }
訪問http://localhost:5555/api-a/hello?accessToken=token返回hello world,訪問http://localhost:5555/api-a/hello返回401錯誤app
eg: 想要將名稱userService-v1的服務映射爲/v1/userService/的路由
在主類中加入自定義規則負載均衡
@Bean public PatternServiceRouteMapper serviceRouteMapper() { return new PatternServiceRouteMapper( "(?<name>^.+)-(?<version>v.+$)", "${version}/${name}" ); }
當匹配表達式的時候,使用此映射規則;不匹配時,採用默認的映射規則框架
?:匹配任意單個字符
*:匹配任意數量的字符
**:匹配任意數量的字符,支持多級目錄maven
路由的規則是經過LinkedHashMap保存的,是有序依次加入的,因此是按照配置的前後順序匹配的。可是properties文件是無序的,若是要想按照前後順序匹配,可使用YAML配置文件ide
使用zuul.ignored-patterns能夠忽略掉API網關對路由的限制,eg:
zuul.ignored-patterns=/**/hello/**
表示任何訪問//hello/的路由都不會獲得映射,得不到返回內容
zuul.prefix=/api
在請求路由時,zuul會默認過濾掉HTTP請求頭信息中的一些敏感信息,防止他們被傳遞到下游的外部服務器。默認的敏感頭信息經過zuul.sensitiveHeaders參數定義,
包括Cookie、Set-Cookie、Authorization三個屬性
zuul.sensitiveHeaders=
#方法1:對指定路由開啓自定義敏感頭 zuul.routes.<router>.customSensitiveHeaders=true #方法2:將指定路由的敏感頭設置爲空 zuul.routes.<router>.sensitiveHeaders=
從訪問的路由能夠看出,訪問成功後,http的url仍然是路由跳轉前的web應用實例地址,而不是路由的地址,此問題致使spring security和shiro在登錄完成後,請求頭信息中的狀態碼爲302,請求響應頭信息中的Location指向了具體的服務實例地址,而請求中的host信息缺指向了路由前的host。故網管進行路由轉發前的Host信息沒有設置正確。
解決方法:
zuul.addHostHeader=true
此解決方案適版本而定
Zuul天生擁有線程隔離和斷路器的自我保護功能,以及對服務調用的客戶端負載均衡功能。可是使用path與url的映射的路由轉發不會採用HystrixCommand來包裝,不具有線程隔離和斷路器的保護功能,也不具有負載均衡的能力
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
ribbon.ConnectTimeout=2000
當此超時時間小於上面的超時時間時,會自動進行重試路由請求
當大於時,不會斷路重連
ribbon.ReadTimeout=3000
短路重連規則同上
#全局關閉 zuul.retryable=false #指定路由關閉 zuul.routes.<route>.retryable=false