spirngcloud Gateway根據(jù)作用范圍劃分為 GatewayFilter 和 GlobalFilter,二者區(qū)別如下:
GatewayFilter:網(wǎng)關(guān)過(guò)濾器,需要通過(guò) spring.cloud.routes.filters 配置在具體路由下,只作用在當(dāng)前路由上或通過(guò)spirng.cloud.default-filters 配置在全局,作用在所有路由上。
GlobalFilter:全局過(guò)濾器,不需要在配置文件中配置,作用在所有的路由上,最終通過(guò) GatewayFilterAdapter 包裝成 GatewayFilterChain 可識(shí)別的過(guò)濾器,它為請(qǐng)求業(yè)務(wù)以及路由的 URI 轉(zhuǎn)換為真實(shí)業(yè)務(wù)服務(wù)請(qǐng)求地址的核心過(guò)濾器,不需要配置系統(tǒng)初始化時(shí)加載,并作用在每個(gè)路由上。
1. 網(wǎng)關(guān)過(guò)濾器GatewayFilter
網(wǎng)關(guān)過(guò)濾器用于攔截并鏈?zhǔn)教幚韜eb請(qǐng)求,可以實(shí)現(xiàn)橫切與應(yīng)用無(wú)關(guān)的需求,比如:安全、訪問(wèn)超時(shí)的設(shè)置等。修改傳入的HTTP請(qǐng)求或傳出HTTP響應(yīng)。Spring Cloud Gateway 包含許多內(nèi)置的網(wǎng)關(guān)過(guò)濾器工廠一共有22個(gè),包括頭部過(guò)濾器、路徑過(guò)濾器、Hystrix過(guò)濾器和重寫請(qǐng)求URL的過(guò)濾器,還有參數(shù)和狀態(tài)碼等其他類型的過(guò)濾器,根據(jù)過(guò)濾器工廠的用途來(lái)劃分,可以分為以下幾種:Header、Parameter、Path、Body、Status、Session、Redirect、Retry、RateLimiter和Hystrix。
1.1 path過(guò)濾器
Path 路徑過(guò)濾器可以實(shí)現(xiàn)URL重寫,通過(guò)重新URL可以實(shí)現(xiàn)隱藏實(shí)際路徑提高安全性,易于用戶記憶和鍵入,易于被搜索引擎收錄等優(yōu)點(diǎn),實(shí)現(xiàn)方式如下:
1.1.1 RewriterPathGatewayFilterFactory
RewritePath 網(wǎng)關(guān)過(guò)濾器工廠采用路徑正則表達(dá)式參數(shù)和替換參數(shù),使用Java正則表達(dá)式來(lái)靈活地重寫請(qǐng)求路徑。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/product/** , /api-gateway/**
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /api-gateway/product/1 重寫為 /product/1
- RewritePath=/api-gateway(?<segment>/?.*), $\{segment}

1.1.2 PrefixPathGatewayFilterFactory
PrefixPath 網(wǎng)關(guān)過(guò)濾器工廠為匹配的 URI 添加指定前綴。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/**
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /1 重寫為 /product/1
- PrefixPath=/product

1.1.3 StripPrefixGatewayFilterFactory
StripPrefix 網(wǎng)關(guān)過(guò)濾器工廠采用一個(gè)參數(shù) StripPrefix,該參數(shù)表示在將請(qǐng)求發(fā)送到下游之前從請(qǐng)求中剝離的路徑個(gè)數(shù)。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/**
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /api/123/product/1 重寫為 /product/1
- StripPrefix=2

1.1.4 SetPathGatewayFilterFactory
SetPath 網(wǎng)關(guān)過(guò)濾器工廠采用路徑模板參數(shù),它提供了一種通過(guò)允許模板化路徑段來(lái)操作請(qǐng)求路徑的簡(jiǎn)單方法,使用了SpringFramework中的URi模板,允許多個(gè)匹配段。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/api/product/{segment}
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /api/product/1 重寫為 /product/1
- SetPath=/product/{segment}

1.2 Parameter參數(shù)過(guò)濾器
AddRequestParameter 網(wǎng)關(guān)過(guò)濾器工廠會(huì)將指定參數(shù)添加至匹配到的下游請(qǐng)求中。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/api-gateway/**
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /api-gateway/product/1 重寫為 /product/1
- RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
# 在下游請(qǐng)求中添加 flag=1
- AddRequestParameter=flag, 1
1.3 Status 狀態(tài)過(guò)濾器
SetStatus 網(wǎng)關(guān)過(guò)濾器工廠采用單個(gè)狀態(tài)參數(shù),它必須為是有效的 Spring HttpStatus。它可以是整數(shù)404或枚舉NOT_FOUND的字符串表示。
spring:
application:
name: gateway-server
cloud:
gateway:
# 路由規(guī)則
routes:
- id: product-service # 路由ID,唯一,一般為各個(gè)服務(wù)名稱
uri: http://localhost:7070/ #目標(biāo)URI,路由到微服務(wù)的地址
predicates:
# 匹配對(duì)應(yīng)的URL請(qǐng)求,將匹配到的請(qǐng)求追加在目標(biāo) URI 之后
- Path=/api-gateway/**
filters: # 網(wǎng)關(guān)過(guò)濾器
# 將 /api-gateway/product/1 重寫為 /product/1
- RewritePath=/api-gateway(?<segment>/?.*), $\{segment}
# 任何情況下,響應(yīng)的HTTP狀態(tài)都將設(shè)置為404
- SetStatus=404 # 404 或者對(duì)應(yīng)的枚舉 NOT_FOUND

2. 自定義過(guò)濾器
即使 Spring Cloud Gateway 自帶許多實(shí)用的 GatewayFilter Factory、Gateway Filter、Global Filter,但是在很多情景下我們?nèi)匀幌M梢宰远x自己的過(guò)濾器,實(shí)現(xiàn)一些謹(jǐn)慎操作。
2.1 自定義網(wǎng)關(guān)過(guò)濾器
自定義網(wǎng)關(guān)過(guò)濾器需要實(shí)現(xiàn)以下兩個(gè)接口:GatewayFilter,Ordered。
public class CustomGatewayFilter implements GatewayFilter, Ordered {
/**
* 過(guò)濾器業(yè)務(wù)邏輯
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定義網(wǎng)關(guān)過(guò)濾器被執(zhí)行");
return chain.filter(exchange); // 繼續(xù)向下執(zhí)行
}
/**
* 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
對(duì)自定義的過(guò)濾器進(jìn)行注冊(cè)
@Configuration
public class GatewayRoutesConfiguration {
@Bean
public RouteLocator routeLocator(RouteLocatorBuilder builder){
return builder.routes().route(r -> r
// 斷言(判斷條件)
.path("/product/**")
// 目標(biāo) URI ,路由到微服務(wù)的地址
.uri("http://localhost:7070")
// 注冊(cè)自定義網(wǎng)關(guān)過(guò)濾器
.filters(new CustomGatewayFilter())
// 路由 ID, 唯一
.id("product-service")).build();
}
}
2.2 自定義全局過(guò)濾器
自定義全局過(guò)濾器需要實(shí)現(xiàn)以下兩個(gè)接口:GlobalFilter, Ordered。通過(guò)全局過(guò)濾器可以實(shí)現(xiàn)全校校驗(yàn),安全性驗(yàn)證等功能。
創(chuàng)建過(guò)濾器,實(shí)現(xiàn)指定接口,添加@component注解即可,一個(gè)網(wǎng)關(guān)既有網(wǎng)關(guān)過(guò)濾器又有全局過(guò)濾器,則執(zhí)行順序,先執(zhí)行全局過(guò)濾器,后執(zhí)行網(wǎng)關(guān)過(guò)濾器
@Component
public class CustomGlobalFilter implements GlobalFilter, Ordered {
/**
* 過(guò)濾器業(yè)務(wù)邏輯
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("自定義全局過(guò)濾器被執(zhí)行");
return chain.filter(exchange); // 繼續(xù)向下執(zhí)行
}
/**
* 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
* @return
*/
@Override
public int getOrder() {
return 0;
}
}
2.3 統(tǒng)一鑒權(quán)
在網(wǎng)關(guān)過(guò)濾器中通過(guò)token判斷用戶是否登錄,完成一個(gè)統(tǒng)一的鑒權(quán)案例
@Component
public class AccessFilter implements GlobalFilter, Ordered {
private Logger logger = (Logger) LoggerFactory.getLogger(AccessFilter.class);
/**
* 過(guò)濾器業(yè)務(wù)邏輯
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 獲取請(qǐng)求參數(shù)
String token = exchange.getRequest().getQueryParams().getFirst("token");
// 業(yè)務(wù)邏輯處理
if(StringUtils.isBlank(token)){
logger.warning("token is null ...");
ServerHttpResponse response = exchange.getResponse();
// 響應(yīng)類型
response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
// 響應(yīng)狀態(tài)碼,HTTP 401 錯(cuò)誤代表用戶沒(méi)有訪問(wèn)權(quán)限
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// 響應(yīng)內(nèi)容
String message = "{\"message\":\"" + HttpStatus.UNAUTHORIZED.getReasonPhrase() + "\"}";
DataBuffer buffer = response.bufferFactory().wrap(message.getBytes());
// 請(qǐng)求結(jié)束,不在繼續(xù)向下請(qǐng)求
return response.writeWith(Mono.just(buffer));
}
// 使用token進(jìn)行身份驗(yàn)證
logger.info("token is OK!");
return chain.filter(exchange);
}
/**
* 過(guò)濾器執(zhí)行順序,數(shù)值越小,優(yōu)先級(jí)越高
* @return
*/
@Override
public int getOrder() {
return 1;
}
}

