yml配置网关路由

Gateway网关路由有两种配置方式,一种用yml配置

新建cloud-gateway-gateway9527模块

image-20200709141933347

pom

不要引入spring web依赖,否则启动不了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<dependencies>
<!--新增gateway-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.kylin</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

yml

image-20200709142451333

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server:
port: 9527
spring:
application:
name: cloud-gateway


eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

主启动类

创建主启动类GateWayMain9527

image-20200709142632928

1
2
3
4
5
6
7
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run( GateWayMain9527.class,args);
}
}

新增网关配置

我们目前不想暴露8001端口,希望在8001外面套一层9527

cloud-provider-payment8001的两个方法做路由映射

image-20200709143010584

image-20200709143148659

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由

- id: payment_routh2
uri: http://localhost:8001
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由


eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

测试

启动7001 8001 9527 http://eureka7001.com:7001/成功注册到Eureka注册中心

image-20200709143716103

访问http://localhost:8001/payment/get/31

image-20200709143845573

访问http://localhost:9527/payment/get/31,也能访问成功

image-20200709143919448

访问http://localhost:9527/payment/lb

dimage-20200709144122986

编码码配置网关路由

Gateway网关路由有两种配置方式,一种用编码配置

我们想通过9527网关访问到外网的百度新闻网址

配置类

编写配置类GateWayConfig

image-20200709144911754

1
2
3
4
5
6
7
8
9
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routes = routeLocatorBuilder.routes();
routes.route("path_rote_atguigu", r -> r.path("/guonei").uri("http://news.baidu.com/guonei")).build();
return routes.build();
}
}

测试

重新启动9527,访问http://localhost:9527/guonei

GIF

实现动态路由

我们当前的路由映射是将地址写死了

image-20200709150148528

而我们应该要达到的效果是同以前一样,通过访问微服务提供者的服务命调用所提供的服务,尽管这个微服务是一个集群。这些客户端都不关心,所以我们要配置GateWay通过微服务名实现动态路由。

yml

image-20200709150555182

通过配置spring.cloud.gateway.discovery.locator.enabled开启从注册中心动态创建路由的功能,利用微服务名进行路由,默认false

此时的spring.cloud.gateway.routeslist集合中的uri属性值为lb://serviceNameuri的协议为lb,表示启用Gateway的负载均衡功能。serviceName时注册中心注册的名称

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #uri的协议为lb,表示启用Gateway的负载均衡功能。
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由

- id: payment_routh2
#uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #uri的协议为lb,表示启用Gateway的负载均衡功能。
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由


eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka

测试

启动7001 8001 8002 9525 访问http://localhost:9527/payment/lb

image-20200709151102797

GIF1511

动态路由配置成功!

Predicate的使用

当我们启动的我们9527的时候会看见控制台输出

image-20200709151428142

我们之前使用Predicate是属性名是predicates说明它能配置多个匹配条件,而我们目前只匹配了Path条件

image-20200709151558412

Route Predicate Factorie

查看官网https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gateway-request-predicates-factories

image-20200709151832266

Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的路由谓词工厂。

Spring Cloud Gateway创建Route对象时,使用RoutePredicateFactory创建Predicate对象,Predicate对象可以赋值给Route。Spring Cloud Gateway包含许多内置的Route Predicate Factories。

所有这些谓词都与HTTP请求的不同属性匹配。您可以将多个路由谓词工厂与逻辑and语句结合使用。

常用的Predicate

image-20200709152152407

image-20200709152504391

After Route Predicate Factory

请求时间满足在配置时间之后

image-20200709152645610

这个时间怎么获得呢?

通过Java提供的ZonoeDateTime.now()获得当地的时间

image-20200709153020096

After=时间 我们把时间改为自己当地的时间后一分钟进行测试

重新启动测试,访问http://localhost:9527/payment/get/31此时再配置时间之前。报错404

image-20200709153445315

配置时间之后在访问,一切正常

image-20200709153358612

同理Before Between也是一样的配置和使用

配置文件predicates加上Cookie

image-20200709154112849

Cookie=username,kylin 只允许cookie键为username 值为kylin

通过命令行curl http://localhost:9527/payment/lb访问

image-20200709154219529

不符合条件报错404

加上cookie访问curl http://localhost:9527/payment/lb --cookie "username=kylin"

image-20200709154447402

访问成功!一切正常

Header Route Predicate Factory

image-20200709154933382

Header=X-Request-Id, \d+请求头要有X-Request-Id属性并且值为整数的正则表达式

访问curl http://localhost:9527/payment/lb -H "X-Request-Id:123"值为整数,一切正常

image-20200709155106342

值为负数curl http://localhost:9527/payment/lb -H "X-Request-Id:-123"

image-20200709155144640

报错404,配置成功!

说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理

Filter的使用

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

image-20200709161254014

路由过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。路由过滤器适用于特定路由。Spring Cloud Gateway内置了多种路由过滤器,他们都有GatewayFilter的工厂类来产生

Filter的声明周期只有两个“pre” 和 “post”。“pre”和 “post” 分别会在请求被执行前调用和被执行后调用。种类分为单一的,和全局的。

Filter,在“pre”类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改,日志的输出、流量监控等,有非常重要的作用

Filter除了分为“pre”和“post”两种方式的Filter外,在Spring Cloud Gateway中,Filter从作用范围可分为另外两种,一种是针对于单个路由的Gateway Filter,它在配置文件中的写法同predict类似;另外一种是针对于所有路由的Global Gateway Filer。现在从作用范围划分的维度来讲解这两种Filer。

单一过滤器GatewayFilter

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#gatewayfilter-factories

全局GlobalFilter

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/#global-filters

image-20200709165641947

自定义全局过滤器

Gateway提供好的过滤器并没有太大的意义,我们可以自定义过滤器编写业务逻辑

将我们配置Predicate注释,编写MyLogGateWayFilter实现GlobalFilter, Ordered,判断是否带有uname参数不能为null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*************come in MyLogGateWayFilter:"+new Date());
//带有uname的请求参数
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname==null){
log.info("********用户名为null,非法用户,/(ㄒoㄒ)/~~");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//添加响应状态码
return exchange.getResponse().setComplete();
}
//放行
return chain.filter(exchange);
}

@Override
public int getOrder() {
return 0;
}
}

启动7001 8001 8002 9527进行测试直接访问http://localhost:9527/payment/lb,访问不拦截

image-20200709165257427

http://localhost:9527/payment/lb?uname=kylin加上uanme参数且值不为null

image-20200709165342802

image-20200709165411114

访问成功!