08 服務閘道器GateWay
GateWay 閘道器
Cloud 元件全家桶中有一個重要的元件就是閘道器,在1.x 版本都是採用的 Zuul閘道器;
但在 2.x 版本中,zuul 的升級一直跳票,SpringCloud 最後自己研發了一個閘道器替代Zuul.
GateWay 為了提供一種簡單而有效的方式來對 API 進行路由 以及提供一些強大的過濾器功能,例如:熔斷、限流、重試等
選擇 GateWay 的原因
Zuul 1 的模型
三大概念
Route(路由):構建閘道器的基本模組,它由ID,目標URI,一系列的斷言
和過濾器組成,如果斷言為true則匹配該路由
Predicate(斷言):開發人員可以匹配 HTTP 請求中的所有內容(例如請求頭或請求引數),如果請求與斷言相匹配則進行路由
Filter(過濾):是SpringCloud框架中的 GateWay的例項,使用過濾器,可以在請求被路由前或者路由之後對請求進行修改
搭建 閘道器9527
- 新建模組cloud-gateway-gateway9527
- pom
閘道器的pom 檔案不需要 web 和 auactor 依賴
<dependencies> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- 引用自己定義的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>com.atguigu.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--eureka client(通過微服務名實現動態路由)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!--熱部署--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
- yml
server:
port: 9527
spring:
application:
name: cloud-gateway
eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
- 主啟動類
@SpringBootApplication @EnableEurekaClient public class GatewayMain9527 { public static void main(String[] args) { SpringApplication.run(GatewayMain9527.class,args); } }
- 修改yml檔案
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_route # 路由的id,沒有規定規則但要求唯一,建議配合服務名
#匹配後提供服務的路由地址
uri: http://localhost:8001
predicates:
- Path=/payment/get/** # 斷言,路徑相匹配的進行路由
- id: payment_route2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
- 測試 啟動 7001 閘道器9527 8001
通過9527 訪問到 8001
predicate 為 true 訪問成功 false 訪問失敗
配置路由的兩種方式
- 在配置檔案yml中配置
- 在配置類中配置
程式碼中注入RouteLocator的Bean
配置類配置
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder){
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_route",
r -> r.path("/guonei") // 相當於 localhost:9527/guonei 轉到下面的百度
.uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}
測試:http://localhost:9527/guonei
動態路由
- 修改yml 檔案
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #開啟從註冊中心動態建立路由的功能,利用微服務名稱進行路由(預設false)
routes:
- id: payment_routh #路由的id,沒有規定規則但要求唯一,建議配合服務名
# uri: http://localhost:8001 #匹配後提供服務的路由地址
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/get/** #斷言,路徑相匹配的進行路由
- id: payment_routh2
# uri: http://localhost:8001
uri: lb://CLOUD-PAYMENT-SERVICE
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
測試,啟動7001,8001,8002,9527
http://localhost:9527/payment/lb
常用Predicate的使用
After/Before/Between
先用一個測試類獲取當前時間
import java.time.ZonedDateTime;
public class Test2 {
public static void main(String[] args) {
//獲取當前時間串
ZonedDateTime now = ZonedDateTime.now();//預設時區
System.out.println(now);
//2021-12-04T14:32:44.032+08:00[Asia/Shanghai] }
}
}
![](https://img2020.cnblogs.com/blog/2316000/202112/2316000-20211204204227454-1201996192.png)
在yml 檔案 中加上
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
# 時間比當前時間晚了一小時
- After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
測試,啟動7001,8001,8002,9527
http://localhost:9527/payment/lb
#指定時間前才能訪問(Before)
- Before=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
#指定時間內才能訪問(Between)
- Between=2021-12-04T15:32:44.032+08:00[Asia/Shanghai],2021-12-04T16:32:44.032+08:00[Asia/Shanghai]
Cookie Route Predicate
需要兩個引數,一個是 Cookie name,一個是正則表示式
路由規則會通過獲取對應的Cookie name 值 和 正則表示式,如果匹配上就會執行路由,如果沒有匹配上則不執行
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
- After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
- Cookie=username,ssyy
Header Route Predicate Factroy
兩個引數 一個是屬性名稱和一個正則表示式,這個屬性值和正則表示式匹配執行
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
# - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
# - Cookie=username,ssyy
- Header=X-Request-Id, \d+ #請求頭要有 X-Request-Id屬性並且值為整數的正則表示式
predicates:
- Path=/payment/lb/** #斷言,路徑相匹配的進行路由
# - After=2021-12-04T15:32:44.032+08:00[Asia/Shanghai]
# - Cookie=username,ssyy
- Header=X-Request-Id, \d+ #請求頭要有 X-Request-Id屬性並且值為整數的正則表示式
- Host=**.angenin.com #Host: xxx.angenin.com 請求是Host必須有**.angenin.com
- Method=GET #只允許get請求訪問
- Path=/payment/lb/** #訪問的url地址有 /payment/lb/ 才能訪問
- Query=username, \d+ #url請求地址必須帶上username引數,並且值必須為整數
Filter
路由過濾器可用於修改進入的 HTTP請求和返回的HTTP響應,路由過濾器只能指定路由進行使用
內建了 許多過濾器 都由 GateWayFilter的工廠產生
GatewayFilter(31種)
Global Filter(10種)
自定義過濾器
新建filter.MyLogGateWayFilter
@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("***************come in MyLogGateWayFilter"+new Date());
String name = exchange.getRequest().getQueryParams().getFirst("name");
if (name == null){
log.info("********使用者名稱為null,非法使用者,T T");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//返回值是過濾器的優先順序,越小優先順序越高(最小-2147483648,最大2147483648)
return 0;
}
}
啟動7001,8001,8002,9527
http://localhost:9527/payment/lb?name=111
帶著 name 就會成功