1.gateway介绍
网关是微服务项目的唯一入口
网管可以:
反向代理 :直接访问网关,网关来决定访问哪个微服务项目
鉴权 :访问网关的时候可以加上token,用来鉴权
流量控制 :这个后来都用sentenal做
熔断
日志监控
2.核心概念:
Router(路由)
路由时构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如果断言为true则匹配
该路由
Predicate(断言)断言说简单点,就是请求匹配条件。断言是定义匹配条件,如果请求符合条件,则该请求匹配断言所属
的路由
Filter(过滤)
指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修
改。
3.Gateway搭建
新创建一个模块
1.引入jar包:
注意,gateway的web依赖要换成webflux
<!--注意我这里没有引入父工程,而是springboot父启动依赖,也不要引入web依赖而是webflux-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!--网关jar-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--客户端负载均衡loadbalancer-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.@EnableDiscoveryClient
3.编写application.yml
server:
port: 8080
spring:
application:
name: alibaba-gateway
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 #注册服务
username: nacos
password: nacos
gateway:
routes:
- id: nacos-consume #唯一 路由id
uri: http://127.0.0.1:8890 #lb://alibaba-gateway-8080 #服务名 lb为负载均衡 也可以使用http:IP+服务端口
predicates: # 断言
- Path=/ts/** # 路径需携带ts
filters:
- StripPrefix=1
- AddRequestHeader= chmy,123 #添加请求头 key,value的形式
4.过滤器:
1.局部过滤器:
spring:
cloud:
gateway:
routes:
filters:
- StripPrefix=1 #路由去掉前缀信息 使用内置过滤器
- AddRequestHeader= chmy,123 #添加请求头 key,value的形式
用这种方式可以打印出来注解@RequestHeader("key")
2.全局请求头
default-filters 的配置和routes平级。
只要配置在 default-filters 下面的过滤器,会对routes配置的所有路由都生效。
spring:
cloud:
gateway:
routes:
filters:
- StripPrefix=1 #路由去掉前缀信息 使用内置过滤器
- AddRequestHeader= chmy,123 #添加请求头 key,value的形式
3.自定义全局路由过滤器:
有时候SpringCloudGateWay提供的过滤器工厂不能满足自己的要求。
可能有时候需要在过滤时做一些其它的逻辑操作。
那么这时候可以选择使用java代码自定义全局过滤器。
有多个过滤器时,Order的值决定了过滤器的执行顺序。
Ordered无法在GateWayFilter中获得token,建议使用注解Order
数值越大优先级越低, 负的越多, 优先级越高。
设置Order的值有两种方式:
1. 实现Ordered接口,并且重写getOrder方法
不使用order:
@Component
public class GateWayFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain
chain) {
// 1.获取请求参数
//1.这里的request并不是servlet中的request
//2.返回值是一个多键的map集合、也就是说这个map集合的键可以重复
MultiValueMap<String, String> params =
exchange.getRequest().getQueryParams();
// 2.获取userName参数
String id = params.getFirst("id");
System.out.println("id===="+id);
// 3.校验,id=3放行
if ("3".equals(id)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);//状态码
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
@Override
public int getOrder() {
return 0;
}
}
2. 使用@Order注解
使用order:
@Component
@Order(0)
public class GateWayFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain
chain) {
// 1.获取请求参数
//1.这里的request并不是servlet中的request
//2.返回值是一个多键的map集合、也就是说这个map集合的键可以重复
MultiValueMap<String, String> params =
exchange.getRequest().getQueryParams();
// 2.获取userName参数
String id = params.getFirst("id");
System.out.println("id===="+id);
// 3.校验
if ("3".equals(id)) {
// 放行
return chain.filter(exchange);
}
// 4.拦截
// 4.1.禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);//状态码
// 4.2.结束处理
return exchange.getResponse().setComplete();
}
}
5.网关限流(注意需要redis3.5)
gateway网关可以限流,但是还是sentinel用的多
令牌桶算法是比较常见的限流算法之一,大概描述如下:
所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
根据限流大小,设置按照一定的速率往桶里添加令牌;
桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之
后,将令牌直接删除;
令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保
证足够的限流
导包:
需求:每个ip地址1秒内只能发送1次请求,多出来的请求返回429错误。
spring cloud gateway 默认使用redis的 RateLimter 限流算法来实现。所以我们要使用首先需要引
入redis的依赖
<!--redis 限流-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
定义KeyResolver:
在启动类添加如下代码, KeyResolver 用于计算某一个类型的限流的KEY也就是说,可以通过
KeyResolver 来指定限流的Key。
//定义一个KeyResolver
@Bean
public KeyResolver ipKeyResolver() {
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return
Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
};
}
application.yml中配置项:
需要修改指定限制流量的配置以及 redis 的配置
redis:
port: 6379
host: 127.0.0.1
password: 123456
args:
key-resolver: "#{@ipKeyResolver}" #用于限流的键的解析器的 Bean 对象的名字。它使用SpEL 表达式根据#{@beanName}从 Spring 容器中获取 Bean 对象
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 1 #令牌桶总容量。
其他限流规则 :
参数限流: key-resolver: "#{@parameterKeyResolver}"
再更改一下方法
@Bean
public KeyResolver parameterKeyResolver()
{
return exchange ->
Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
URI限流 : key-resolver: "#{@pathKeyResolver}"
/**
* 限流规则配置类 多个bean时其中一个bean添加@Primary注解
*/
@Configuration
public class KeyResolverConfiguration
{
@Bean
public KeyResolver pathKeyResolver()
{
return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
}
}
6.其他:
以前版本的gateway:会自动发现这两个微服务,路径就是ip+端口号+服务名+路径
如:http://127.0.0.1:8070/alibaba-user-consumer-8090/user/findUserById?id=3
但是现在新版本就是上面的那样关闭这个enabled: false
gateway:
discovery:
locator:
enabled: true #表明gateway开启服务注册和发现的功能,ateway为每一个服务创建了一
个router,这个router将以服务名开头的请求路径转发到对应的服务。