SpringCloud進擊 | 六淺出:服務閘道器 - 過濾器(Zuul Filter)【Finchley版本】
1.前言
上一節:SpringCloud進擊 | 五淺出:服務閘道器 - 路由(Zuul Router)【Finchley版本】
Zuul 本身是一系列過濾器的整合,那麼他當然也就提供了自定義過濾器的功能,Zuul 提供了四種過濾器:前置過濾器,路由過濾器,錯誤過濾器,簡單過濾器。實現起來也非常簡單,只需要編寫一個類去實現 Zuul 提供的介面 - ZuulFilter。
2.準備
延用上一節的專案,並分別啟動以下模組:
- 服務註冊中心:wei-eureka-server,埠號:8090
- 服務提供者:wei-service-provider,埠號:8010、8011
- 服務消費者:wei-consumer-ribbon,埠號:8020
服務註冊中心(http://localhost:8090/)檢視服務,如下,註冊成功:
首先,可以正常訪問服務:http://localhost:8060/api/consumerGroup/demo/info?name=tester
Hi,tester,我是服務,我被呼叫了,服務名為:wei-service-provider,埠為:8011
如果不能正常訪問,可以看看上一節 SpringCloud進擊 | 六淺出:服務閘道器 - 路由(Zuul Router)【Finchley版本】
如上,準備工作完成。
3.進擊
3.1.pom.xml 依賴
檔案與上一節相同,無需改造
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.wei</groupId> <artifactId>wei-gateway-zuul</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>wei-gateway-zuul</name> <description>Demo project for Spring Cloud Zuul</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties> <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> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3.2.application.yml 配置檔案
檔案與上一節相同,無需改造
server:
port: 8060 # 自定義程式啟動埠
spring:
application:
name: wei-gateway-zuul # 指定進行服務註冊時該服務的名稱,服務與服務之間相互呼叫一般都是根據這個name
eureka:
client:
service-url:
defaultZone: http://localhost:8090/eureka/ # 指定進行服務註冊的地址
zuul:
routes: # 配置路由對映
wei-service-provider: /providerGroup/** # 服務名稱對映。給指定的服務做對映,當前配置是將/wei-service-provider/**對映為/providerGroup/**
consumerGroup: # 保證唯一
#url: http://localhost:8020/ # url繫結對映
serviceId: wei-consumer-ribbon # 給指定的服務做對映
path: /consumerGroup/** # path繫結對映。配置對映的路徑,當前配置是將/wei-consumer-ribbon/**對映為/consumerGroup/**
prefix: /api
ribbon:
eureka:
enabled: false # 在eureka中禁用 ribbon 的負載均衡
wei-consumer-ribbon:
ribbon: # 給配置serviceId對應的服務指定ribbon負載均衡,從listOfServers配置的服務地址中分配服務,多個用半形逗號分隔
listOfServers: http://localhost:8010/, http://localhost:8011/
3.3.Zuul 過濾器
通過繼承 ZuulFilter 抽象類,編寫自定義 Filter。
package com.wei.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
@Component
public class WeiZuulFilter extends ZuulFilter {
/**
* 型別包含 pre、post、route、error
* pre:在路由代理之前執行
* route:代理的時候執行
* error:出現錯的時候執行
* post:在route 或者是 error 執行完成後執行
*
* 過濾器的型別,它決定過濾器在請求的哪個生命週期中執行
* 這裡定義為pre,表示會在請求被路由之前執行
*
* @return 過濾器型別
*/
@Override
public String filterType() {
return "pre";
}
/**
* Zuul filter 為鏈式過濾器,多個filter按順序執行,通過數字指定
* 數字越大,優先順序越低
*
* @return 執行順序
*/
@Override
public int filterOrder() {
return 0;
}
/**
* 是否啟用該過濾器
* 判斷該過濾器是否需要被執行。這裡我們直接返回了true,因此該過濾器對所有請求都會生效
* 實際運用中我們可以利用該函式來指定過濾器的有效範圍
*
* @return true:啟用過濾器 / false:禁用過濾器
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* 過濾器的具體邏輯實現Demo
*
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
System.out.println("[ Demo For Zuul Filter ] Execute!");
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
System.out.println("[ Demo For Zuul Filter ] token parameter is empty!");
// 使用 Zuul 過濾此種場景的請求,不對其進行路由
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(401);
requestContext.setResponseBody("token is empty!");
} else {
System.out.println("[ Demo For Zuul Filter ] test success!");
}
return null;
}
}
3.4.啟動類
檔案與上一節相同,無需要改造
package com.wei;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
* 註解@EnableZuulProxy,開啟Zuul功能,自帶熔斷
*/
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class WeiGatewayZuulApplication {
public static void main(String[] args) {
SpringApplication.run(WeiGatewayZuulApplication.class, args);
}
}
好了,到此,Zuul Filter 過濾器就已新增完成。其實只是增加並實現了一個自定義 ZuulFilter 類。
執行這個啟動類。
4.測試
訪問:http://localhost:8060/api/consumerGroup/demo/info?name=tester
瀏覽器輸出:
token is empty!
後臺日誌列印:
前端看一看,請求返回結果狀態是401。如此,說明 Zuul 過濾器已經在正常工作。
那我們把 token 引數加上:token=token_test
訪問:http://localhost:8060/api/consumerGroup/demo/info?name=tester&token=token_test
瀏覽器列印:
Hi,tester,我是服務,我被呼叫了,服務名為:wei-service-provider,埠為:8010
後臺日誌列印:
有木有,通過過濾器,Zuul 正確路由到了配置檔案配置好的 加了字首(/api) 對映(/consumerGroup)的 /demo/info 介面。
5.總結
上面的程式碼實現過程中,當通過繼承 ZuulFilter 抽象類後,需要我們重寫它的四個方法:
- filterType():過濾器的型別。它決定過濾器在請求的哪個生命週期中執行。其型別包含 pre、post、route、error。
- pre:在路由代理之前執行
- route:代理的時候執行
- error:出現錯的時候執行
- post:在route 或者是 error 執行完成後執行
- filterOrder():過濾器的執行順序。當請求在一個階段中存在多個過濾器時,需要根據該方法返回的值來依次執行。通過數字指定,數字越大,優先順序越低。
- shouldFilter():判斷該過濾器是否需要被執行。這裡我們直接返回了true,因此該過濾器對所有請求都會生效。實際運用中我們可以利用該函式來指定過濾器的有效範圍。
- run():過濾器的具體邏輯。這裡我們只是簡單實現了一下,使用 Zuul 過濾入參沒有 token 場景的請求,不對其進行路由。
官方參考文件:https://springcloud.cc/spring-cloud-netflix.html
下一節,請繼續關注:SpringCloud進擊 | 一深入:高可用的服務註冊中心【Finchley版本】