小白學SpringCloud(五):路由閘道器(Zuul)
在微服務的架構下,各個服務一般會有各自的網路地址,在這樣的情況下外部客戶端的呼叫可能會形成雜亂無章的局面。這時候我們就可以使用微服務閘道器Zuul這個元件,我們讓所有的客戶端請求全部請求Zuul,再由Zuul統一的去請求各個服務。
一、Zuul簡介
Zuul是Netflix開源的微服務閘道器,他可以和Eureka,Ribbon,Hystrix等元件配合使用。Zuul元件的核心是一系列的過濾器,這些過濾器可以完成以下功能:
- 身份認證和安全: 識別每一個資源的驗證要求,並拒絕那些不符的請求
- 審查與監控:
- 動態路由:動態將請求路由到不同後端叢集
- 壓力測試:逐漸增加指向叢集的流量,以瞭解效能
- 負載分配:為每一種負載型別分配對應容量,並棄用超出限定值的請求
- 靜態響應處理:邊緣位置進行響應,避免轉發到內部叢集
- 多區域彈性:跨域AWS Region進行請求路由,旨在實現ELB(ElasticLoad Balancing)使用多樣化
Spring Cloud對Zuul進行了整合和增強。目前,Zuul使用的預設是Apache的HTTP Client,也可以使用Rest Client,可以設定ribbon.restclient.enabled=true.。
二、建立一個api-gateway工程
這裡我們使用IntelliJ IDEA進行展示。
1.首先建立一個Zuul專案
使用IDEA建立一個專案
中間有一步我們選擇Zuul選項和SpringBoot版本,如圖
然後下一步就可以建立好了
2.新增@EnableZuulProxy註解
這個註解只需要在springboot工程的啟動application類上就好了
@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
public class ApiGetwayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGetwayApplication.class, args);
}
然後在配置檔案中新增config的配置,具體可以見
我們先來隨便訪問一下client端的env介面
然後我們通過zuul服務的埠+專案名/介面名這種方式來訪問一下這個介面
可以看到,同樣訪問到了結果。
另外,我們也可以在配置檔案中更加細粒度控制路由路徑:
# 表示只要HTTP請求是 /client1開始的,就會轉發到服務id為client1的服務上面
zuul:
routes:
client1:
path:/client1/** // 路由路徑
serviceId: client1 // 服務id
client2:
path:/client2/** // 路由路徑
serviceId: client2 // 服務id
需要注意的是,使用Zuul預設不會將Cookie的資訊帶入服務端,所以我們需要在配置檔案中進行配置,將敏感頭設定為空即可:
zuul:
sensitiveHeaders:
二、服務過濾
zuul不僅只是路由,並且還能過濾,做一些安全驗證。我們來新建一個Filter並且繼承ZuulFilter
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
/**
* @Author: lllx
* @Description:
* @Date: Created on 17:54 2018/7/10
* @Modefied by:
*/
public class MyFilter extends ZuulFilter {
/*返回一個字串代表過濾器的型別
pre:路由之前
routing:路由之時
post: 路由之後
error:傳送錯誤呼叫
我們可以通過匯入FilterConstants這個常量類中的屬性來返回
*/
@Override
public String filterType() {
return PRE_TYPE;
}
//過濾的順序,Zuul中也自定義了很多過濾器,呼叫的順序即通過這個方法返回的大小,越小越靠前。我們可以通過FilterConstants這個常量類中定義好的過濾器-1來返回
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER -1;
}
//這裡可以寫邏輯判斷,是否要過濾,本文true,永遠過濾。
@Override
public boolean shouldFilter() {
return true;
}
//過濾器的具體邏輯。可用很複雜,包括查sql,nosql去判斷該請求到底有沒有許可權訪問。
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//從url引數獲取如果沒有token這個引數就不允許請求
String token = request.getParameter("token");
if(StringUtils.isEmpty(token)){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
我們可以通過這樣的方式去自定義一個個的過濾器。