Gateway—网关服务

⼀、网关介绍

使用服务网关作为接口服务的统⼀代理,前端通过网关完成服务的统⼀调用

Gateway—网关服务_第1张图片

  • 网关可以干什么?
    路由:接口服务的统⼀代理,实现前端对接⼝服务的统⼀访问
    过滤:对用户请求进行拦截、过滤(用户鉴权)、监控
    限流:限制用户的访问流量
  • 常用的网关
    Nginx
    Spring Cloud Netflix zuul
    Spring Cloud Gateway

Nginx通常被用作应用服务器网关(Tomcat集群,Redis集群,前端浏览器网关),
zuul或者gateway通常被用作服务网关(springcloud微服务)

二、Gateway使用

  • 文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/

Route: 路由是网关的基本组成部分,它是由id、目标uri、断⾔组成,如果断⾔为true,则匹配该路由,转向到当前路由的URI
Predicate:断⾔,用户请求的匹配规则
Filter:过滤器,用于对请求进行前置、后置处理(可以在网关实现对请求或相应的加工处理)

Gateway—网关服务_第2张图片

  • 添加依赖
<dependency>
	<groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
  • 添加配置
server:
 port: 9999
spring:
 application:
 	name: gateway-server
 cloud:
 	gateway:
 		routes:
		 # 配置api-service1路由规则
		 # id随便起
		 - id: api-service1
		 uri: http://localhost:8001
		 # 断言规则:路径里有product的跳转
		 # http://localhost:9999/product/query  —>  http://localhost:8001/product/query
		 predicates:
		 	- Path=/product/**
		 
		 # 配置api-service2路由规则
		 - id: api-service2
		 uri: http://localhost:8002
		 predicates:
		 -	 Path=/order/**

三、Predicate断言

SpringCloud Gateway提供了多种断⾔匹配的⽅式:
After
Before
Between
Cookie
Header
Host
Method
Path
Query
RemoteAddr
Weight

3.1 Path

根据请求路径的正则匹配

server:
 port: 9999
spring:
 application:
 	name: gateway-server
 cloud:
 	gateway:
 		routes:
		 # 配置api-service1路由规则
		 # id随便起
		 - id: api-service1
		 uri: http://localhost:8001
		 # 断言规则:路径里有product的跳转
		 # http://localhost:9999/product/query  —>  http://localhost:8001/product/query
		 predicates:
		 	- Path=/product/**
		 
		 # 配置api-service2路由规则
		 - id: api-service2
		 uri: http://localhost:8002
		 predicates:
		 	- Path=/order/**

3.2 Query

根据请求携带的参数匹配路由

spring:
 application:
	 name: gateway-server
 cloud:
	 gateway:
	 	routes:
 			- id: aaa
			 uri: http://localhost:8001
			 predicates:
			 # http://localhost:9999/product/query?name=wang ---> http://localhost:8001/product/query?name=wang
			 	- Query=name
			 
			 - id: bbb
			 uri: http://localhost:8002
			 predicates:
			 #如果请求url中带有pwd参数 ---> http://localhost:8002
			 	- Query=pwd

3.3 Header

根据Header中携带的参数匹配

spring:
 application:
	 name: gateway-server
 cloud:
	 gateway:
	 	routes:
 			- id: aaa
			 uri: http://localhost:8001
			 predicates:
			 # 带key为token的请求头
			 	- Header=token
			 
			 - id: bbb
			 uri: http://localhost:8002
			 predicates:
			 # 带key为aa值为haha的请求头
			 	- Header=aa,haha

3.4 Host

根据Host主机名进行匹配转发,如果我们的接口只允许**.yuqiyu.com域名进行访问

spring:
  cloud:
    gateway:
      routes:
        - id: blog
          uri: http://blog.yuqiyu.com
          predicates:
            - Host=**.yuqiyu.com
         #  或者指定某ip可以访问 http://192.168.155.11:8002

3.5 组合示例

相同的Predicate也可以配置多个,请求的转发是必须满足所有的Predicate后才可以进行路由转发

spring:
  cloud:
    gateway:
      routes:
        - id: blog
          uri: http://blog.yuqiyu.com
          predicates:
            - Method=GET
            - Host=**.yuqiyu.com
            - Path=192.168.1.56/24    

四、filters过滤器

gateway网关可以对用户的请求和响应进行处理,gateway提供了多个内置的过滤器,不同的过滤器可以完成不同的请求或者响应的处理

4.1 内置网关过滤器

spring:
 application:
	 name: gateway-server
 cloud:
	 gateway:
		 routes:
			 - id: aaa
			 uri: http://localhost:8001
			 predicates:
			 - Path=/red/aaa/query/**
			 filters:
			 # 对请求添加请求头
			 - AddRequestHeader=token,wahahaawahaha
			 # 对请求路径添加请求参数
			 - AddRequestParameter=username, ergou
			 # 修改请求状态
			 - SetStatus=404
			 # 对url为*/red/*的替换为*/*
			 # http://localhost:9999/red/product/query  —>  http://localhost:8001/product/query
			 - RewritePath=/red(?>/?.*), $\{segment}
			 # 对匹配断言的url去掉前两个参数(最终和上面的效果相同)
			 - StripPrefix=2

4.2 自定义服务过滤器

4.2.1 创建网关过滤器 - 实现GatewayFilter

  • 实现GatewayFilter, Ordered
public class MyFilter01 implements GatewayFilter, Ordered {

	 @Override
	 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	 ServerHttpRequest request = exchange.getRequest();
	 ServerHttpResponse response = exchange.getResponse();
	 System.out.println("---------------⾃定义过滤器");
	 return chain.filter(exchange);
	 }
	 //设置此过滤器优先级 0最优先
	 @Override
	 public int getOrder() {
	 return 0;
	 }
}
  • 配置过滤器
@Configuration
public class GatewayConfig {

	 @Bean
	 public RouteLocator routeLocator(RouteLocatorBuilder builder){
	 System.out.println("-----------------------init");
	 RouteLocator routeLocator = builder.routes().route( r->
	 r.path("/product/**") 							// predicates
	 .filters(f->f.filters( new MyFilter01() )) 	// filters
	 .uri("http://localhost:8001") 					//uri
	 ).build();
	 return routeLocator;
	 }
}

4.2.2 创建网关过滤器 - 继承AbstractNameValueGatewayFilterFactory

相当于扩展Gateway内置的网关过滤器
创建⼀个类继承AbstractNameValueGatewayFilterFactory,类名必须以GatewayFilterFactory结尾,类名前⾯的部分即为当前自定义网关过滤器的名字
添加@Component注解,注册到Spring容器

@Component
public class MyFilterGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

	 @Override
	 public GatewayFilter apply(NameValueConfig config) {
	 System.out.println("name:"+config.getName());
	 System.out.println("value:"+config.getValue());
	 
	 //创建⾃定义⽹关过滤器并返回
	 GatewayFilter gatewayFilter = new GatewayFilter() {
	 @Override
	 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	 System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~⾃定义网关过滤器");
	 return chain.filter(exchange);
	 }
	 };
	 return gatewayFilter;
	 }
}
  • 配置yml
spring:
 application:
	 name: gateway-server
 cloud:
	 gateway:
 		routes:
		 - id: bbb
		 uri: http://localhost:8002
		 predicates:
		 - Path=/order/**
		 filters:
		 - MyFilter=aa,bb

4.3 全局过滤器

上述过滤器,都是配置在某个路由/服务中,称之为 ⽹关服务过滤器 ,Gateway提供了内置的全局过滤器,会拦截过滤所有到达网关服务器的请求。
内置的全局过滤器默认⽣效,⽆需开发者干预。
根据业务的需求我们也可以⾃定义全局过滤器以实现对所有网关请求的拦截和处理(验证token)

@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {

	 @Override
	 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
	 
	 System.out.println("----------------------------------------------MyGlobalFilter");
	 List<String> list = exchange.getRequest().getHeaders().get("token");
	 if (list != null && list.size()>0){
		 String token = list.get(0);
		 System.out.println("token:"+token);
		 return chain.filter(exchange);
		 }else{
		 //如果没有token,或者token过期
		 ServerHttpResponse response = exchange.getResponse();
		 //设置响应头
		 response.getHeaders().add("Content-Type","application/json;charset=utf-8");
		 //设置状态码
		 response.setStatusCode(HttpStatus.UNAUTHORIZED);
		 // 封装响应数据
		 String str = "";
		 DataBuffer dataBuffer = response.bufferFactory().wrap(str.getBytes());
		 return response.writeWith(Mono.just(dataBuffer));
		 }
	 }
	 @Override
	 public int getOrder() {
		 return 0;
	 }
}

五、Gateway动态路由配置

如果在Gateway网关的路由配置中,直接将服务的ip port配置进去,将导致:
1.如果服务的地址变更,必须要重新配置gateway的路由规则
2.如果服务采⽤集群部署,则不能实现负载均衡
所以Gateway搭配eureka实现动态路由(将Gateway配置中uri改为eureka中服务的名字即可 添加 lb 可以实现负载均衡)

  • 在Gateway服务中添加eureka-server依赖
<dependency>
 <groupId>org.springframework.cloudgroupId>
 <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
server:
 port: 9999
spring:
 application:
 	name: gateway-server
 main:
 	web-application-type: reactive
 cloud:
 	gateway:
		 routes:
			 - id: aaa
			 # uri改为eureka中服务消费者的name即可 添加 lb 可以实现负载均衡
			 uri: lb://api-service1
			 predicates:
			 - Path=/product/**
			 - id: bbb
			 uri: lb://api-service2
			 predicates:
			 - Path=/order/**
eureka:
 client:
	 service-url:
		defaultZone: http://localhost:8761/eureka

六、网关限流

通过限制用户的请求进⼊到服务中,有效控制应用系统的QPS,达到保护系统的目的

Gateway是基于令牌桶算法,使用redis作为“桶”结合顾虑器实现了网关限流

  • 令牌桶算法就是所有进⼊网关的请求必须从令牌桶中得到令牌才可以进行服务调用,我们可以通过控制令牌桶的容量、令牌的产生速率达到控制用户流量的目的
    Gateway—网关服务_第3张图片
  • 添加依赖
<dependency>
	 <groupId>org.springframework.bootgroupId>
	 <artifactId>spring-boot-starter-data-redis-reactiveartifactId>
dependency> <dependency>
	 <groupId>org.apache.commonsgroupId>
	 <artifactId>commons-pool2artifactId>
	 <version>2.9.0version>
dependency>
  • 配置keyResolver
@Configuration
public class AppConfig {
	 @Bean
	 public KeyResolver keyResolver() {
	 //http://localhost:9999/order/query?user=1
	 //使⽤请求中的user参数的值作为令牌桶的key
	 //return exchange ->Mono.just(exchange.getRequest().getQueryParams().getFirst("user"));
	 return exchange -> Mono.just(exchange.getRequest().getURI().getPath());
	 }
}
  • 配置服务的限流规则
server:
 port: 9999
spring:
 application:
	 name: gateway-server
 main:
	web-application-type: reactive
 	cloud:
 		gateway:
 			routes:
				 - id: aaa
				 uri: lb://api-service1
				 predicates:
					 - Path=/product/**
					 - 
				 - id: bbb
				 uri: lb://api-service2
				 predicates:
					 - Path=/order/**
				 filters:
				 - name: RequestRateLimiter
				 args:
					 redis-rate-limiter.replenishRate: 1 #令牌桶每s的填充速度(每秒增加一个可以访问的线程)
					 redis-rate-limiter.burstCapacity: 2 # 令牌桶容量(最多两个并发访问)
					 redis-rate-limiter.requestedTokens: 1
					 key-resolver: "#{@keyResolver}"
	redis:
		 host: 47.96.11.185
		 port: 7001
		 password: qfedu123
		 database: 0
		 lettuce:
			pool:
			 max-active: 10
			 max-wait: 1000
			 max-idle: 5
			 min-idle: 3
eureka:
 client:
	 service-url:
 		defaultZone: http://localhost:8761/eureka

你可能感兴趣的:(gateway,spring,cloud,java)