传统的接口实现:
客户端 - 》 控制器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()); // 监控远程请求地址
}
}
}