Zuul 是Spring Cloud 子項目Spring Cloud Netflix的一個組件,它是Netflix對ApiGateway實現的一份答卷,應用很是普遍。常見的功能以下java
OK,既然標題提到zuul動態路由,此文章主要介紹下zuul動態路由,那麼咱們寫個小demo看看zuulnginx
<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
註解開啓Zuul@EnableZuulProxy @EnableEurekaClient @SpringCloudApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class,args); } @Bean public PreFilter preFilter() { return new PreFilter(); } @Bean public RoutingFilter routingFilter() { return new RoutingFilter(); } @Bean public PostFilter postFilter() { return new PostFilter(); } @Bean public ErrorFilter errorFilter() { return new ErrorFilter(); } }
三、application.properties
中配置Zuul應用的基礎信息,如:應用名、服務端口等。spring.application.name=api-gateway server.port=9091
#反響代理配置 #這裏的配置相似nginx的反響代理 #當stripPrefix=true的時候 (http://127.0.0.1:8181/api/user/list -> http://192.168.1.100:8080/user/list) #當stripPrefix=false的時候(http://127.0.0.1:8181/api/user/list -> http://192.168.1.100:8080/api/user/list) zuul.routes.api.path=/api/** #代理前綴默認會從請求路徑去除 zuul.routes.api.stripPrefix=false
#提升超時配置(有的同窗碰到第一次代理時都是timeout,須要配置以下配置)git
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:60000程序員
ribbon.ConnectTimeout: 3000github
ribbon.ReadTimeout: 60000spring
在服務網關中定義過濾器只須要繼承zuulfltier抽象類實現其定義的四個抽象函數就可對請求進行攔截與過濾。api
好比下面的例子,定義了一個Zuul過濾器,實現了在請求被路由以前檢查請求中是否有accessToken
參數,如有就進行路由,若沒有就拒絕訪問,返回401 Unauthorized
錯誤。安全
public class AccessFilter extends ZuulFilter { private static Logger log = 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 ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); Object accessToken = request.getParameter("accessToken"); if(accessToken == null) { log.warn("access token is empty"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); return null; } log.info("access token ok"); return null; } }
自定義過濾器的實現,須要繼承ZuulFilter
,須要重寫實現下面四個方法:架構
filterType
:返回一個字符串表明過濾器的類型,在zuul中定義了四種不一樣生命週期的過濾器類型,具體以下:
pre
:能夠在請求被路由以前調用routing
:在路由請求時候被調用post
:在routing和error過濾器以後被調用error
:處理請求時發生錯誤時被調用filterOrder
:經過int值來定義過濾器的執行順序shouldFilter
:返回一個boolean類型來判斷該過濾器是否要執行,因此經過此函數可實現過濾器的開關。在上例中,咱們直接返回true,因此該過濾器老是生效。run
:過濾器的具體邏輯。須要注意,這裏咱們經過ctx.setSendZuulResponse(false)
令zuul過濾該請求,不對其進行路由,而後經過ctx.setResponseStatusCode(401)
設置了其返回的錯誤碼,固然咱們也能夠進一步優化咱們的返回,好比,經過ctx.setResponseBody(body)
對返回body內容進行編輯等。在實現了自定義過濾器以後,還須要實例化該過濾器才能生效,還須要在應用主類中增長四個過濾器的實例化。app
一、第一次代理請求是鏈接超時(timeout) 須要配置 進行以下配置
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:60000 ribbon.ConnectTimeout: 3000 ribbon.ReadTimeout: 60000
二、com.netflix.discovery.TimedSupervisorTask(線程池拒絕策略異常),相信不少人都碰到了這個問題,度娘了有的說不影響,確實是不影響,可是程序員都有強迫症。
java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@427829d8 rejected from java.util.concurrent.ThreadPoolExecutor@5f0345ff[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0] at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2048) ~[na:1.7.0_79] at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:821) [na:1.7.0_79] at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1372) [na:1.7.0_79] at java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:110) ~[na:1.7.0_79] at com.netflix.discovery.TimedSupervisorTask.run(TimedSupervisorTask.java:62) ~[eureka-client-1.4.11.jar:1.4.11] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) [na:1.7.0_79] at java.util.concurrent.FutureTask.run(FutureTask.java:262) [na:1.7.0_79] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:178) [na:1.7.0_79] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:292) [na:1.7.0_79] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_79] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_79] at java.lang.Thread.run(Thread.java:745) [na:1.7.0_79]
ok廢話很少說,直接上解決方案,將對應的eurake版本升級,此問題應該是eurake自帶的bug
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Dalston.RELEASE</version> // 注意關鍵點在這 <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>