网关Gateway
- 一、网关初识
- 二、网关的使用
- 1.创建项目并引入依赖
- 2.编写网关配置
- 3.启动服务并测试
- 三.查看网关路由规则列表
- 四.路由服务的负载均衡
- 五.断言和过滤
- 1.断言Predicate
- 1.1.The Path Route Predicate Factory(路径断言工厂)
- 1.2.The After Route Predicate Factory(after路由断言工厂)
- 1.3.The Before Route Predicate Factory(before路由断言工厂)
- 1.4.The Between Route Predicate Factory(between路由断言工厂)
- 1.5.The Cookie Route Predicate Factory(cookie路由断言工厂)
- 1.6.The Header Route Predicate Factory(header路由断言工厂)
- 1.7.The Method Route Predicate Factory(method路由断言工厂)
- 2.过滤Filter
- 2.1.The AddRequestHeader GatewayFilter Factory
- 2.2.The AddRequestParameter GatewayFilter Factory
- 2.3.The AddResponseHeader GatewayFilter Factory
- 2.4.The PrefixPath GatewayFilter Factory
- 2.5.The StripPrefix GatewayFilter Factory
- 3.自定义全局Filter基础使用
一、网关初识
官方地址:SpringCloud Gateway
网关统一了服务的入口,可以方便实现对众多服务接口进行管控,对访问服务的身份认证,防报文重放与防数据篡改,功能调用的业务鉴权,响应数据的脱敏,流量与并发控制,甚至基于API调用的计量或者计费等等。更通俗理解,网关可以看成是路由转发以及过滤器的共同作用,路由转发接受一切外界的请求,然后转发到后端的微服务中;而过滤器在服务网关中可以完成一系列的横切功能,比如权限校验,限流以及监控等。
在SpringCloud的官网中则指出其提供了一个在SpringMVC之上构建API网关的库。SpringCloudGateway旨在提供一种简单而有效的方法来路由到API,并为API提供横切关注点,比如:安全性、监控/度量和弹性。
SpringCloud Gateway在特性方面,官网中也给出了说明:
-基于Spring Framework 5、Project Reactor和Spring Boot 2.0构建
-能够在任何请求属性上匹配路由,即动态路由
-断言和过滤器对于路由是特定的
-路径重写
-请求速率限制
二、网关的使用
1.创建项目并引入依赖
<!--引入gateway网关依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2.编写网关配置
本文当中继续使用之前的商品和用户服务模块,这里给出相关配置信息:
server:
port: 9000
spring:
application:
name: PRODUCT
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址
-------------------------------------------------------------------------------------
server:
port: 8999
spring:
application:
name: USER
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址
网关的配置如下:
server:
port: 8989
spring:
application:
name: GATEWAY
cloud:
gateway:
routes:
- id: user_route #指定路由的唯一标识
uri: http://localhost:8999 #指定路由服务的地址
predicates:
- Path=/user/** #指定路由规则
- id: product_route
uri: http://localhost:9000
predicates:
- Path=/product/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址
3.启动服务并测试
在商品服务的业务层中有如下代码:
@RestController
@Slf4j
@RequestMapping("/product")
public class ProductController {
@Value("${server.port}")
private String port;
@GetMapping("/find")
public String find(){
log.info("商品服务调用成功,端口为{}", port);
return "服务调用成功,服务提供端口: " + port;
}
}
在用户服务的业务层中的代码如下,在用户服务中使用OpenFeign组件调用商品服务。
@RestController
@Slf4j
@RequestMapping("/user")
public class UserController {
@Autowired
private ProductClient productClient;
@GetMapping("/find")
public String user(){
log.info("用户服务调用成功....");
String msg = productClient.find();
return msg;
}
}
写入Gateway的启动类,然后启动相应服务,
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {
public static void main(String[] args){
SpringApplication.run(GatewayApplication.class, args);
}
}
服务启动之后,在浏览器中进入http://localhost:8989/user/find可以访问用户服务,进入http://localhost:8989/product/find可以访问商品服务。
解析:一般而言,我们访问商品服务或者是用户服务,使用的访问地址是http://localhost:9000/product/find以及http://localhost:8999/user/find;但是在配置网关之后,访问商品服务时使用http://localhost:8989/product/find,但是在网关中并没有该路径,而它真正的执行过程可以理解为在网关配置文件中的断言的路由规则找到路径为/product/**,并且匹配成功,从而将http://localhost:8989替换为该路由中的uri,即http://localhost:9000,最后组装为http://localhost:8989/product/find,即可访问到正确的路径地址。而用户服务中的实现也是同种道理。当然有时候我们在一个controller业务层中可能有多个接口调用,因此在实现过程中断言中的路径规则我们写成/product/*,并加上@RequestMapping(“/product”)注解,即可匹配到product下的所有接口路径。
三.查看网关路由规则列表
Gateway提供路由访问规则列表的web界面,但是默认是关闭的,如果想要查看服务路由规则可以在配置文件中开启:
management:
endpoints:
web:
exposure:
include: "*" #开启所有web端点暴露
同时在该项目中加入如下依赖,提供监控功能:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
启动服务之后在浏览器中进入http://localhost:8989/actuator/gateway/routes,即可在web界面中看到配置的服务路由规则:
四.路由服务的负载均衡
现有路由配置方式,都是基于服务地址写死的路由转发。所以我们可以对原有的路由配置进行更改,使其能够根据服务名称进行路由转发同时实现负载均衡。
server:
port: 8989
spring:
application:
name: GATEWAY
cloud:
gateway:
discovery:
locator:
enabled: true #开启根据服务名动态获取路由
routes:
- id: user_route #指定路由的唯一标识
# uri: http://localhost:8999 #指定路由服务的地址
uri: lb://USER #lb指代loadBalance负载均衡,USER指代服务名
predicates:
- Path=/user/** #指定路由规则
- id: product_route
# uri: http://localhost:9000
uri: lb://PRODUCT #lb指代loadBalance负载均衡,PRODUCT指代服务名
predicates:
- Path=/product/**
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka #指定服务注册中心的地址
management:
endpoints:
web:
exposure:
include: "*" #开启所有web端点暴露
可以发现的是,uri不再对主机和端口进行写死,而是采用了lb(LoadBalance)加服务名提供路由地址。当路径匹配之后,会从注册中心对匹配该服务名的服务进行负载均衡处理。
五.断言和过滤
在官网中,有这么一幅图,很好的诠释了网关的工作原理:
在这个图中,Gateway Handler Mapping和Gateway Web Handler就是我们所称的断言,而后续的一系列的filter就是过滤器。由图我们可以知道,当客户端向Spring Cloud Gateway发送请求的时候,如果网关处理程序映射器确定请求与路由匹配,则将其发送到网关Web处理程序。然后经过一系列的过滤器处理,最后到达服务端。
1.断言Predicate
断言其实可以认为是网关的前置处理,当请求到达网关时,会先经过前置处理,满足断言则放行,不满足则立即返回,比如上述例子中的路径匹配就是前置处理。
当然,在官网中给出了路由断言工厂(Route Predicate Factories),这里我们选几个断言进行介绍:
1.1.The Path Route Predicate Factory(路径断言工厂)
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
这个其实我们都不陌生了,就是之前一直使用的路径匹配。
1.2.The After Route Predicate Factory(after路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
这个断言的含义就是代表该路由规则必须要在指定时间之后才能生效,这里的时间使用的是java中的ZonedDateTime。
1.3.The Before Route Predicate Factory(before路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
同理,这个断言的含义就是该路由规则要在指定时间之前才能生效,时间同样是使用java中的ZonedDateTime。
1.4.The Between Route Predicate Factory(between路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
这个断言的含义代表路由规则必须要指定时间之间才能生效。
1.5.The Cookie Route Predicate Factory(cookie路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
顾名思义,这个断言的含义就是指携带指定cookie请求才能访问。
1.6.The Header Route Predicate Factory(header路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
这个断言的含义就是指请求必须要含有指定的请求头才能生效。
1.7.The Method Route Predicate Factory(method路由断言工厂)
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
这个断言是指基于请求方式的访问。
2.过滤Filter
过滤相当于网关的后置处理,当请求满足断言的所有条件之后,会向后端服务转发,在向后端服务转发之前会经过一些过滤操作。
路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由筛选器的作用域是特定路由。springcloudgateway包括许多内置的GatewayFilter工厂。而它的功能就是当我们有很多个服务时,比如下图中的user-service、order-service、product-service等服务,客户端请求各个服务的Api时,每个服务都需要做相同的事情,比如鉴权、限流、日志输出等,那我们可以统一在网关处进行处理操作。
在官网中给出GatewayFilter Factories,同样,我们选出一些内置的过滤器进行介绍:
2.1.The AddRequestHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: https://example.org
filters:
#添加请求头X-Request-red,值为blue
- AddRequestHeader=X-Request-red, blue
这个过滤器的主要作用就是用来给路由对象的所有转发请求加入指定请求头信息。
2.2.The AddRequestParameter GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_request_parameter_route
uri: https://example.org
filters:
- AddRequestParameter=red, blue
这个过滤器的主要作用就是用来给路由对象的所有转发请求加入指定请求参数。
2.3.The AddResponseHeader GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: https://example.org
filters:
- AddResponseHeader=X-Response-Red, Blue
这个过滤器的作用就是用来给路由对象的所有转发请求的响应加入指定头部信息。
2.4.The PrefixPath GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://example.org
filters:
- PrefixPath=/mypath
这个过滤器的含义是用来给路由对象的所有转发请求的url加入指定前缀信息,比如访问网关匹配地址/list,前缀路径是/mypath,最后转发到后端的服务地址就是url+前缀路径+地址栏路径,url/mypath/list。
2.5.The StripPrefix GatewayFilter Factory
spring:
cloud:
gateway:
routes:
- id: nameRoot
uri: https://nameservice
predicates:
- Path=/name/**
filters:
- StripPrefix=2
这个过滤器的含义是用来给路由对象的所有转发请求的url去掉指定2个前缀,比如访问地址是/product/list,StripPrefix=1,则最终的访问地址是/list。
3.自定义全局Filter基础使用
自定义全局Filter就是当内置的过滤器不能满足现实需求,则可以自定义过滤器来处理,当然所有请求都要经过全局Filter才能转发到后端。
@Configuration
public class CustomGlobalFilter implements GlobalFilter, Ordered {
@Override
//exchange封装了request和reponse
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//httprequest对象
ServerHttpRequest request = exchange.getRequest();
//httpresponse对象
ServerHttpResponse response = exchange.getResponse();
System.out.println("经过全局filter处理....");
//放行filter
Mono<Void> filter = chain.filter(exchange);
System.out.println("响应回来filter处理");
return filter;
}
排序,用来指定filter执行顺序,默认顺序按照自然数字进行排序,-1在所有filter之前执行
@Override
public int getOrder() {
return 0;
}
}
当然这里只是给出了自定义过滤器的基本使用,具体的代码实现还是要根据业务来进行编写。