Gateway
一、简介
1、什么是微服务网关
后端写完所有的微服务之后,最终是要交给前端去调用。我们都知道每个微服务都有各自的端口号,如果前端直接通过IP加端口的方式去调用微服务会很麻烦。如果想对请求增加限制也会变得十分困难。这个时候微服务网关就出现了。API网关的职责有身份验证、监控、负载均衡、缓存、请求分片与管理、静态响应处理,最重要的功能是和外界联系。
常见的API网关实现方式有Zuul,traefix,Spring Cloud Gateway等等。目前主流的微服务网关是Spring Cloud Gateway。
2、Spring Cloud Gateway核心概念
路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL,一组断言工厂和一组Filter组成。
断言(predicates):java8中的断言函数,Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自Http Request中的任何信息。当断言为真时,则匹配路由。
过滤器(filter):对请求和响应进行过滤
二、简单使用案例
1、新建一个cloud-gateway项目
2、加入依赖
<!--gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
//还有一些其它依赖
3、添加配置文件
配置文件说明:
- id :指定该路由的名字(唯一)
- uri:指定需要路由的服务器地址和端口
- predicates:断言,指定请求匹配规则
server:
port: 9527
#直接指定服务器地址的写法
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
# 负载均衡的写法,路由uri写成注册中心中服务的名称
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client: #服务提供者provider注册进eureka服务列表内
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
除了yml配置文件的方式,还可以使用代码注入Bean的方式来设置网关路由
下面就是将网关匹配的路径/guonei发送到Http://news.baidu.com/guonei网址
@Configuration
public class GatewyConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_atguigu",r->r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
@Bean
public RouteLocator customRouteLocator2(RouteLocatorBuilder builder){
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("path_route_atguigu2",r->r.path("/guoji").uri("http://news.baidu.com/guoji")).build();
return routes.build();
}
}
三、配置细讲
1、Predicate使用
predicate就是用来写明路由的匹配规则,只有符合匹配规则的请求才会配对,并发送请求到对应的route进行处理。
常用的Route Predicate有:
- After:指定时间之后
- Before:指定时间之前
- Betwwen:指点时间之间
- Cookie:包含指定cookie并且值相同
- Header:包含指定请求头并且值相同
- Host:指定主机地址
- Method:指定请求方式
- Path:指定请求路径匹配
- Query:包含指定请求参数
(细节查看官网)
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
- After=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] # 断言,路径相匹配的进行路由
#- Before=2020-02-05T15:10:03.685+08:00[Asia/Shanghai] # 断言,路径相匹配的进行路由
#- Between=2020-02-02T17:45:06.206+08:00[Asia/Shanghai],2020-03-25T18:59:06.206+08:00[Asia/Shanghai]
#- Cookie=username,zzyy
#- Header=X-Request-Id, \d+ # 请求头要有X-Request-Id属性并且值为整数的正则表达式
#- Host=**.atguigu.com
- Method=GET
- Query=username, \d+ # 要有参数名username并且值还要是整数才能路由
四、Filter使用
Filter路由过滤器可以用来修改进入Http请求和返回的Http响应,路由过滤器只能指定路由进行处理。
Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生
Spring Cloud Gateway 内置路由过滤器:
- pre / post
- GatewayFilter / GlobalFilter
1、常用Filter
常用Filter有很多,细节可以看官网
举个使用的例子:请求头加上一对请求头,名称为X-Request-Id值为1024
routes:
- id: payment_routh #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-provider-payment #匹配后的目标服务地址,供服务的路由地址
#uri: http://localhost:8001 #匹配后提供服务的路由地址
filters:
- AddRequestParameter=X-Request-Id,1024 #过滤器工厂会在匹配的请求头加上一对请求头,名称为X-Request-Id值为1024
predicates:
- Path=/paymentInfo/** # 断言,路径相匹配的进行路由
- Method=GET,POST
2、自定义Filter
自定义Filter的使用频率是要比默认提供的使用频率高的。根据自己的需求来创建Filter
例子:创建一个自定义全局GlobalFiter,在请求前验证请求参数是否包含uname
@Component //必须加,必须加,必须加
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
{
System.out.println("time:"+new Date()+"\t 执行了自定义的全局过滤器: "+"MyLogGateWayFilter"+"hello");
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
System.out.println("****用户名为null,无法登录");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
//设置等级,值越小的Filter越先执行
@Override
public int getOrder()
{
return 0;
}
}