傳統的接口實現:
客戶端 - 》 控制器A -》 服務1 -》 dao
客戶端 - 》 控制器B -》 服務2 -》 dao
網關實現:
客戶端 - 》gateway - > 服務1/服務2 -》 dao
gateway 好處
1. 去掉控制器,將http請求無縫接入服務接口
2. 統一出入參格式
3. 統一異常規范
4. 自動檢測服務接口規范
客戶請求 -> gateway:9001 -> 服務1: 8081 | 服務2: 8082 | other: 808n
具體的微服務IP 端口都不同 ,客戶端就不用關心每個微服務的ip端口了,直接通過geteway訪問即可(類似nginx網關路由)
通過geteway的yml或.properties配置好映射關系,服務啟動后自動會去eureka獲取微服務
在SpringCloud 全家桶中網關中提供Zuul 服務組件,后來升級為Gateway
微服務網關有
路由轉發:根據請求的url中的特征匹配到具體微服務中
權限控制:實現了GlobalFilter接口,請求的url中 可以對token進行驗證
過濾: 如特殊字段 字符的過濾 再做熔斷提示
服務限流:並發請求微服務的閾值
黑白名單控制等
一、准備
創建網關工程 pom.xml 加入:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<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>
啟動類配置:
@EurekaClient
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
1.1 :路由
server:
port: 8080
spring:
application:
name: gateway
devtools: // 熱部署 修改自動重啟 pom需要引入
restart:
enabled: true
cloud:
gateway:
routes:
- id: service_name # 微服務名
uri: https://127.0.0.1:8081 # 微服務uri
predicates: # 匹配規則關鍵字
- Path=/** # 任意字符都可以可以進行路由 routes中一些配置與zuul類似寫法的區別
routes:
- id: service_name
uri: https://127.0.0.1:8082
predicates:
- Path=/**
discovery: # 開啟服務名稱轉發 注:開啟redis限流此處即可不需要
locator:
enabled: true # true配置 訪問前綴必須有微服務名稱 否則 無法訪問
# 注冊中心地址
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:9091/eureka
instance:
instance-id: 127.0.0.1:9091
prefer-ip-address: true
1.2 權限
@Component
class TokenFilter implements GlobalFilter, Ordered { // GlobalFilter內置的全局過濾器 , Ordered執行順序級別(很多攔截器)
@Override
int getOrder() { return 1; } // 值越小越先執行
@Override
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("Authroization");
// 然后根據token結合業務做處理
// 比如:拿token與jwt或redis 校驗 或者只判斷是否有token 如果有就放行給微服務去處理 都可以 一般不放行
// 還有做的完善點的 專門啟用一個鑒權客戶端服務端工程,然后在鑒權服務端
...
return chain.filter(exchange);
}
}
1.3 限流
令牌桶概念:勻速生產令牌 - > 令牌桶容量 - > user去消耗令牌
以下用redis實現桶
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
spring:
redis:
host: 192.168.92.10
port: 6379
database: 0
cloud:
gateway:
routes:
- id: service_name
uri: lb://service_name
predicates:
- Path=/serviceName/**
filters:
- RewritePath=/serviceName/(?<segment>.*), /$\{segment} # 由於服務名轉發注掉 又想根據項目名訪問
- name: RequestRateLimiter # 攔截器 對上面routes進行攔截
args:
key-resolver: '#{@uriKeyResolver}' # redis限流入口
redis-rate-limiter.replenishRate: 1 # 令牌桶每1s 向令牌桶加一次令牌
redis-rate-limiter.burstCapacity: 2 # 令牌桶每1s之內 最多訪問2次
// redis限流入口
@Bean
public KeyResolver uriKeyResolver(){
return new KeyResolver(){
@Override
public Mono<String> resolve(ServerWebExchange exchange){
// 獲得用戶請求的地址 進行限流
return Mono.just(exchange.getRequest().getRemoteAddress().getHostAddress()); // 監控遠程請求地址
}
}
}