咱們先看一個圖,若是按照consumer and server(最初的調用方式),以下所示java
這樣咱們要面臨以下問題:spring
1. 用戶面臨着一對N的問題既用戶必須知道每一個服務。隨着服務的增多不免會....express
2.消費端(在這裏多是服務,也有可能爲controller等),如何進行安全控制?好比說對調用者身份的驗證,防止爬蟲,或者限制IP在必定時間內的請求數?apache
3.即使作了這些驗證,那麼每一個消費端都要重複的編寫代碼?會不會形成冗餘?json
那麼解決這些問題,咱們不妨進行改造一下:後端
這樣咱們能夠將一對N轉成了一對一,用戶只需跟網關打交道就行了,這樣咱們能夠在網關裏處理身份驗證等安全性問題,何樂而不爲呢安全
Zuul 是在雲平臺上提供動態路由,監控,彈性,安全等服務框架,Zuul 至關因而設備和 Netflix 流應用的 Web 網站後端全部請求的前門。同時Zuul使用一系列不一樣類型的過濾器,使咱們可以快速,靈活地將功能應用於咱們的安全服務。這些過濾器可幫助咱們執行如下功能:app
身份驗證和安全性 - 識別每一個資源的身份驗證要求並拒毫不符合要求的請求。框架
洞察和監測 - 跟蹤有意義的數據和統計數據,以便爲咱們提供準確的生產視圖。less
動態路由 - 根據須要動態路由請求到不一樣的後端羣集。
壓力測試 - 逐漸增長羣集流量以衡量性能。
加載Shedding - 爲每種類型的請求分配容量並刪除超出限制的請求。
靜態響應處理 - 直接在邊緣創建一些響應,而不是將它們轉發到內部羣集
多區域彈性 - 跨AWS區域的路由請求,以便擴大咱們的ELB使用範圍。
1.首先咱們先添加spring-cloud對zuul的依賴:
compile('org.springframework.cloud:spring-cloud-starter-zuul')
2.咱們建立application.yml配置文件:
spring: application: name: gateway-server server: port: 8080 eureka: client: service-url: defaultZone: http://localhost:8000/eureka zuul: routes: orders: path: /orders/** #url: http://www.baidu.com serviceId: ORDER-SERVER pay: path: /pay/** serviceId: PAY-SERVER
3.編寫啓動類
package com.zhibo.springcloud.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; @SpringBootApplication @EnableDiscoveryClient @EnableZuulProxy public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class,args); } }
注意@EnableZuulProxy是@EnableZuulServer的一個超集,咱們能夠經過源代碼發現 org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration繼承了ZuulServerAutoConfiguration
4.1 filter(過濾器)是一個很重要的概念,它能夠在真正的請求以前進行必要的業務操做,好比說驗證等。那麼在zuul中過濾器最核心的接口爲IZuulFilter,該接口定義很是簡單:
/* * Copyright 2013 Netflix, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.zuul; import com.netflix.zuul.exception.ZuulException; /** * BAse interface for ZuulFilters * * @author Mikey Cohen * Date: 10/27/11 * Time: 3:03 PM */ public interface IZuulFilter { /** * a "true" return from this method means that the run() method should be invoked * * @return true if the run() method should be invoked. false will not invoke the run() method */ boolean shouldFilter(); /** * if shouldFilter() is true, this method will be invoked. this method is the core method of a ZuulFilter * * @return Some arbitrary artifact may be returned. Current implementation ignores it. * @throws ZuulException if an error occurs during execution. */ Object run() throws ZuulException; }
而ZuulFilter是一個實現IZuulFilter接口的抽象類,這個類在接口的基礎上又添加了以下抽象方法
/** * to classify a filter by type. Standard types in Zuul are "pre" for pre-routing filtering, * "route" for routing to an origin, "post" for post-routing filters, "error" for error handling. * We also support a "static" type for static responses see StaticResponseFilter. * Any filterType made be created or added and run by calling FilterProcessor.runFilters(type) * * @return A String representing that type */ abstract public String filterType(); /** * filterOrder() must also be defined for a filter. Filters may have the same filterOrder if precedence is not * important for a filter. filterOrders do not need to be sequential. * * @return the int order of a filter */ abstract public int filterOrder();
我在這裏簡單解釋一下這幾個方法做用:
filterType:定義過濾器的類型:常見的有pre(預處理階段) post(請求原始服務以前) error(發生錯誤之後) route(請求原始服務以後)
filterOrder:定義多個過濾器的優先級,值越小優先級越高
shouldFilter:值若是爲true,那麼終會執行run()方法
run : 過濾器實際上執行的內容
4.2 RequestContext是ConcurrentMap的一個子類,這個類能夠拿到HttpServletRequest與HttpServletResponse,同時這個類當中的數據能夠被多個zuulFilter共享,其中有幾個方法值得咱們注意如下:
getCurrentContext() 獲取ThreadLocal中的RequestContext對象
setSendZuulResponse() 若是設置爲false那麼將終止對原始地址的路由
setResponseStatusCode() 設置http的狀態響應碼
addZuulResponseHeader() 設置響應頭,經過這個方法咱們能解決響應時中文亂碼問題
setResponseBody() 設置響應體
4.3 代碼示例:實現用戶名驗證
package com.zhibo.springcloud.zuul; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; @Component public class ValidateUserZuulFilter extends ZuulFilter { /** * * @return */ @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext requestContext = RequestContext.getCurrentContext(); HttpServletRequest request = requestContext.getRequest(); String loginName = request.getParameter("loginName"); if (loginName == null || !"admin".equals(loginName)) { requestContext.setSendZuulResponse(false); requestContext.setResponseStatusCode(500); Gson gson = new GsonBuilder().create(); requestContext.addZuulResponseHeader("content-type", "application/json;charset=utf-8"); requestContext.setResponseBody(gson.toJson(new ResponseEntity("沒有登陸名", HttpStatus.CONFLICT))); return null; } return null; } }
在這篇文章裏已經很詳細的說明了,請你們參考:周立的Springcloud超時總結