admin管理员组文章数量:1633830
所有代码都在github上:https://github/demonruin/cloud2020/tree/master
Route(路由)
1、构架pom文件,这里面需要将web包去掉,因为Gateway的底层是webflux,而webflux和web是冲突的,只能有一个,需要注意!
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache/POM/4.0.0"
xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache/POM/4.0.0 http://maven.apache/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloud2020</artifactId>
<groupId>com.king.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-gateway9527</artifactId>
<dependencies>
<!--新增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>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.king.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!--<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</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>
</project>
2、构建main方法入口,因为gateway也需要注册进注册中心,所以也需要添加注解@EnableEurekaClient
package com.king.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloudflix.eureka.EnableEurekaClient;
/**
* created by king on 2020/4/23 1:19 下午
*/
@SpringBootApplication
@EnableEurekaClient
public class GatewayMain9527 {
public static void main(String[] args) {
SpringApplication.run(GatewayMain9527.class,args);
}
}
3、构建yml文件,此处是简单的路由配置,等演示成功后,后边会更改为动态路由配置
server:
port: 9527
spring:
application:
name: cloud-gateway
cloud:
gateway:
routes:
- id: payment_routh1 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#单机
defaultZone: http://localhost:7001/eureka
# 集群
#defaultZone: http://eureka7001:7001/eureka,http://eureka7002:7002/eureka,http://eureka7003:7003/eureka
instance:
instance-id: gateway9527
prefer-ip-address: true #访问路径可以显示ip地址
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认30s)
#lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认90s,超时将剔除服务
#lease-expiration-duration-in-seconds: 2
4、此时测试http://localhost:8001/payment/get/1 、http://localhost:8001/payment/lb 和 http://localhost:9527/payment/get/1 、http://localhost:9527/payment/lb得到的结果是一样是,说明我们的9527gateway已经实现了路由功能
而Gateway网关实现路由有两种方法:
第一种就是yml配置方式,上述就是这一种
第二种就是在代码中注入RouteLocator的bean,代码如下:
package com.king.springcloud.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* created by king on 2020/4/23 2:21 下午
* 配置了一个id为myroutebaidu1的路由规则,
* 当访问地址http://localhost:9527/guone时会自动转发到地址: http://news.baidu/guonei
*/
@Configuration
public class GatewayConfiguration {
@Bean
public RouteLocator customerRouterLocator1(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("myroutebaidu1", r -> r.path("/guonei").uri("http://news.baidu/guonei")).build();
return routes.build();
}
@Bean
public RouteLocator customerRouterLocator2(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("myroutebaidu2", r -> r.path("/guoji").uri("http://news.baidu/guoji")).build();
return routes.build();
}
//注意:此处的path需要和uri的最后路径保持一致,不一致会报错找不到的,这个game就是反例~~
@Bean
public RouteLocator customerRouterLocator3(RouteLocatorBuilder builder) {
RouteLocatorBuilder.Builder routes = builder.routes();
routes.route("myroutebaidu3", r -> r.path("/mygame").uri("http://news.baidu/game")).build();
return routes.build();
}
}
可以实现路由到百度新闻的某个标签模块
上面是gateway实现路由的简单配置,默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。下面给出了动态路由创建配置:
1、动态路由配置yml,修改部分:
①是添加了discovery.locator.enabled:true开启了动态路由功能
②是修改uri为 lb://开头 + 注册中心微服务名 (注意服务名小写) (lb代表注从注册中心获取微服务,有LoadBalance功能)
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh1 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service #uri以lb://开头(lb代表从注册中心获取服务)
# uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
- id: payment_routh2 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service #uri以lb://开头(lb代表从注册中心获取服务)
# uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
2、启动eureka7001、provider8001、provider8002和 gateway9527服务,然后测试访问http://localhost:9527/payment/get/1,根据响应的结果端口号8001和8002轮训出现,即可确定实现了动态路由功能。
Predicates(断言)
Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理。
官网例子地址:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/3.0.0.M1/reference/html/#gateway-request-predicates-factories
下面举例一下 predicates断言的几种类型:
- Loaded RoutePredicateFactory [After] :时间点之后服务可访问
- Loaded RoutePredicateFactory [Before] :时间点之前服务可访问
- Loaded RoutePredicateFactory [Between] :两个之间点之间服务可访问,
datetime2
参数必须是后于datetime1
- Loaded RoutePredicateFactory [Cookie] :请求服务需要带cookie
- 此处可使用curl来进行测试 curl http://localhost:9527/payment/lb --Cookie "username=king"
- Loaded RoutePredicateFactory [Header] :请求服务需要带header
- 请求头要有X-Request-Id属性并且值为整数的正则表达式 curl http://localhost:9527/payment/lb -H "X-Request-Id:1234"
- Loaded RoutePredicateFactory [Host] :请求头中的header中需要包含host的内容为somehost等这些
- curl http://localhost:9527/payment/lb -H "host:www.anotherhost"
- curl http://localhost:9527/payment/lb -H "host:www.somehost"
- Loaded RoutePredicateFactory [Method] :请求为post请求
- curl http://localhost:9527/payment/lb -X POST
- Loaded RoutePredicateFactory [Path] : 路径相匹配的进行路由
- Loaded RoutePredicateFactory [Query] :要有参数名称并且是正整数才能路由 没演示成功
- Loaded RoutePredicateFactory [ReadBodyPredicateFactory] :官网没看见,不做解释了
- Loaded RoutePredicateFactory [RemoteAddr] :需要ip在1-24区间的可以访问通过,比如 192.168.1.10
- Loaded RoutePredicateFactory [Weight] :这条路线会将此百分比的流量转发到这里,与其他配合服务使用。
- Loaded RoutePredicateFactory [CloudFoundryRouteService] :官网没找到,不做解释了
这里官网给出的时间点是美国时区的,所以我们需要工具转换一下为中国/上海时区
import java.time.ZonedDateTime;
/**
* created by king on 2020/4/23 3:44 下午
*/
public class T1 {
public static void main(String[] args) {
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
//输出为 2020-04-23T15:45:46.581+08:00[Asia/Shanghai]
}
}
yml的例子我就直接全粘贴了,不再一个个去操作了
spring:
application:
name: cloud-gateway
cloud:
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: payment_routh1 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service #uri以lb://开头(lb代表从注册中心获取服务)
# uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
# - Weight=group2, 8
- id: payment_routh2 #路由的ID,没有固定规则但要求唯一,建议配合服务名
uri: lb://cloud-payment-service #uri以lb://开头(lb代表从注册中心获取服务)
# uri: http://localhost:8001 #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
# - After=2020-04-23T15:45:46.581+08:00[Asia/Shanghai] #此时间点后才能访问
# - Before=2020-04-23T18:45:46.581+08:00[Asia/Shanghai] #此时间点前才能访问
# - Between=2020-04-23T15:45:46.581+08:00[Asia/Shanghai],2020-04-24T15:45:46.581+08:00[Asia/Shanghai] #datetime1和datetime2区间请求可访问。datetime2参数必须是后于datetime1
# - Cookie=username,king #请求服务需要带cookie,此处可使用curl来进行测试 curl http://localhost:9527/payment/lb --Cookie "username=king"
# - Header=X-Request-Id, \d+ #请求服务需要带header,请求头要有X-Request-Id属性并且值为整数的正则表达式 curl http://localhost:9527/payment/lb -H "X-Request-Id:1234"
# - Host=**.somehost,**.anotherhost #请求头中的header中需要包含host的内容为somehost等这些 curl http://localhost:9527/payment/lb -H "host:www.anotherhost" 或 curl http://localhost:9527/payment/lb -H "host:www.somehost"
# - Method=POST #请求为post请求 curl http://localhost:9527/payment/lb -X POST
# - Query=username, \d+ #要有参数名称并且是正整数才能路由 没演示成功 curl http://localhost:9527/payment/lb?username=1,但是浏览器输入请求这个地址成功测试完成
# - RemoteAddr=192.168.1.1/24 #需要ip在1-24区间的可以访问通过,比如 192.168.1.10
# - Weight=group1, 2 #这条路线会将大约80%的流量转发到上边儿,将大约20%的流量转发到这里,与其他配合服务使用。
Filter(过滤)
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。Spring Cloud Gateway内置了多种路由过滤器,他们都由GatewayFilter的工厂 类来产生。
springcloud gateway的Filter的 :
- 生命周期有两个 pre(业务逻辑之前) 和 post(业务逻辑之后)
- 种类有两种Gateway Filter 和 GlobalFilter
- Gateway Filter 30种 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/3.0.0.M1/reference/html/#gatewayfilter-factories
- GlobalFilter 10种 https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/3.0.0.M1/reference/html/#global-filters
一般我们是通过实现自定义全局GlobalFilter过滤器,来完成操作的
自定义全局GlobalFilter过滤器搭建演示:
1、新建MyLogGlobalFilter,在类上加注解@Component ,并实现 GlobalFilter, Ordered两个接口,并自定义拦截规则
- 先通过exchange获取参数
- 验证参数是否合法
- 参数不合法:通过exchange的response设置状态码,然后响应出去
- 完成操作后通过 chain.filter(exchange)过滤链 传递下去
package com.king.springcloud.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
/**
* created by king on 2020/4/23 5:05 下午
*/
@Component
@Slf4j
public class MyLogGlobalFilter implements GlobalFilter, Ordered {
/**
* 1.先通过exchange获取参数
* 2.验证参数是否合法
* 参数不合法:通过exchange的response设置状态码,然后响应出去
* 3.完成操作后通过 chain.filter(exchange)过滤链 传递下去
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*********come in MyLogGlobalFilter: "+new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if(uname ==null){
log.info("uname 为空,非法用户,请出去~~~~");
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return response.setComplete();
}
return chain.filter(exchange);
}
//加载过滤器的顺序,一般数字越小,优先级越高
@Override
public int getOrder() {
return 0;
}
}
2、通过url请求测试Filter是否成功 http://localhost:9527/payment/lb?uname=asga、http://localhost:9527/payment/lb?u=asga
通过uname有值的得到放行,而没有uname参数的直接返回错误~
到此,springcloud 的Gateway 新网关的演示结束了~后续有新的会继续补充~~~
本文标签: 断言网关路由SpringCloudGateway
版权声明:本文标题:SpringCloud Gateway网关的路由、断言、过滤配置 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.elefans.com/dianzi/1729177125a1188859.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论