文章目錄
-
- 1 概述
- 2 準備工作
-
- 2.1 服務注冊
- 2.2 服務消費
- 3 基本使用
- 4 請求過濾
- 5 其他配置
-
- 5.1 比對規則
- 5.2 忽略路徑
- 5.3 字首
學習在 Spring Cloud 中使用 Zuul 實作服務網關,包括基本使用、請求過濾、忽略路徑、字首等功能。它是 Netflix 家族成員之一。
1 概述
由于每一個微服務的位址都有可能發生變化,無法直接對外公布這些服務位址,基于安全以及高内聚低耦合等設計,我們有必要将内部系統和外部系統做一個切割。
一個專門用來處理外部請求的元件,就是服務網關,常用功能:
- 權限問題統一處理
- 資料剪裁和聚合
- 簡化用戶端的調用
- 可以針對不同的用戶端提供不同的網關支援
在 Spring Cloud 中,網關主要有兩種實作方案:
Zuul
和
Spring Cloud Gateway
。
Zuul 是 Netflix 公司提供的網關服務,主要有如下功能:
- 權限控制,可以做認證和授權
- 監控
- 動态路由
- 負載均衡
- 靜态資源處理
Zuul 中的功能基本上都是基于過濾器來實作,它的過濾器有幾種不同的類型:
- PRE
- ROUTING
- POST
- ERROR
2 準備工作
2.1 服務注冊
建立 Spring Boot 項目
zuul-client-provider
,作為我們的服務提供者,添加
Web/Eureka Client
依賴,如下:
最終的依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
項目建立成功後,修改
application.properties
配置檔案,将 zuul-client-provider 注冊到 Eureka Server 上(服務注冊中心使用 Eureka Server ),如下:
# 目前服務的名稱
spring.application.name=zuul-client-provider
# 目前服務的端口
server.port=6000
# 服務注冊中心位址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
接下來,啟動 Eureka Server ,待服務注冊中心啟動成功後,再啟動 zuul-client-provider ,兩者都啟動成功後,通路 http://127.0.0.1:1111 可以看到 zuul-client-provider 的注冊資訊。
當然 zuul-client-provider 也可以叢集化部署,下面對 zuul-client-provider 進行打包,之後我們在指令行啟動兩個 provider 執行個體:
java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6000
java -jar zuul-client-provider-0.0.1-SNAPSHOT.jar --server.port=6001
最後在 zuul-client-provider 提供一個 hello 接口,用于後續服務消費者 zuul-client-consumer 來消費,如下:
@RestController
public class ProviderController {
@Value("${server.port}")
Integer port; // 支援啟動多個執行個體,做負載均衡,用端口區分
@GetMapping("/hello")
public String hello() {
return "hello cxy35: " + port;
}
}
2.2 服務消費
建立 Spring Boot 項目
zuul-client-consumer
,作為我們的服務消費者,添加
Web/Eureka Client/Zuul
依賴,如下:
最終的依賴如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
項目建立成功後,修改
application.properties
配置檔案,将 zuul-client-consumer 注冊到 Eureka Server 上(服務注冊中心使用 Eureka Server ),如下:
# 目前服務的名稱
spring.application.name=zuul-client-consumer
# 目前服務的端口
server.port=6002
# 服務注冊中心位址
eureka.client.service-url.defaultZone=http://127.0.0.1:1111/eureka
接着,在項目啟動類上添加
@EnableZuulProxy
注解,開啟網關代理,如下:
@SpringBootApplication
@EnableZuulProxy // 開啟網關代理
public class ZuulClientConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulClientConsumerApplication.class, args);
}
}
接下來,啟動 zuul-client-consumer ,通路 http://127.0.0.1:1111 可以看到 zuul-client-consumer 的注冊資訊。
3 基本使用
配置完成後,通路 http://127.0.0.1:6002/zuul-client-provider/hello ,會自動通過 Zuul 的代理通路到 zuul-client-provider 中對應的的接口,無需知道其真實的位址。在這個通路位址中, zuul-client-provider 就是要通路的服務名稱, /hello 則是要通路的服務接口。
當然, Zuul 中的路由規則也可以自己配置,如下:
# Zuul 中的路由規則配置
# zuul.routes.cxy35.path=/cxy35/**
# zuul.routes.cxy35.service-id=zuul-client-provider
# 簡化配置
zuul.routes.zuul-client-provider=/cxy35/**
上面配置表示滿足
/cxy35/**
這個比對規則的請求,将被轉發到 zuul-client-provider 執行個體上。比如:http://127.0.0.1:6002/cxy35/hello
4 請求過濾
對于來自用戶端的請求,可以在 Zuul 中進行預處理,例如權限判斷等。
在
zuul-client-consumer
中定義一個簡單的權限過濾器,如下:
@Component
public class PermissionFilter extends ZuulFilter {
/**
* 過濾器類型,權限判斷一般是 pre
*
* @return
*/
@Override
public String filterType() {
return "pre";
}
/**
* 過濾器優先級
*
* @return
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否過濾
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 核心的過濾邏輯寫在這裡
*
* @return 這個方法雖然有傳回值,但是這個傳回值目前無所謂
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();//擷取目前請求
String username = request.getParameter("username");
String password = request.getParameter("password");
if (!"cxy35".equals(username) || !"123456".equals(password)) {
//如果請求條件不滿足的話,直接從這裡給出響應
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.addZuulResponseHeader("content-type", "text/html;charset=utf-8");
ctx.setResponseBody("非法通路,無權限");
}
return null;
}
}
重新開機 zuul-client-consumer ,接下來,發送請求必須帶上 username 和 password 參數,否則請求不通過,比如:http://127.0.0.1:6002/cxy35/hello?username=cxy35&password=123456
5 其他配置
5.1 比對規則
例如有兩個服務,一個叫 provider ,另一個叫 provider-hello ,在做路由規則設定時,假如出現了如下配置:
zuul.routes.provider=/provider/**
zuul.routes.provider-hello=/provider/hello/**
此時,如果通路一個位址:
http://127.0.0.1:6002/provider/hello/123
,會出現沖突。實際上,這個位址是希望和 provider-hello 這個服務比對的,這個時候,隻需要把配置檔案改為 yml 格式就可以了,因為 yml 格式的配置是有序的。
5.2 忽略路徑
預設情況下,Zuul 注冊到 Eureka 上之後, Eureka 上的所有注冊服務都會被自動代理。如果不想給某一個服務做代理,可以忽略該服務,配置如下:
zuul.ignored-services=provider2
上面這個配置表示忽略 provider2 服務,此時就不會自動代理 provider2 服務了。
當然,也可以忽略某一類位址,配置如下:
zuul.ignored-patterns=/**/hello/**
這個表示請求路徑中如果包含 hello ,則不做代理。
5.3 字首
可以統一給路由加字首,配置如下:
zuul.prefix=/cxy35
這樣,以後所有的請求位址自動多了字首
/cxy35
。
- Spring Cloud 教程合集(微信左下方閱讀全文可直達)。
- Spring Cloud 教程合集示例代碼:https://github.com/cxy35/spring-cloud-samples
- 本文示例代碼:https://github.com/cxy35/spring-cloud-samples/tree/master/spring-cloud-zuul
掃碼關注微信公衆号 程式員35 ,擷取最新技術幹貨,暢聊 #程式員的35,35的程式員# 。獨立站點:https://cxy35.com