yml配置网关路由
Gateway网关路由有两种配置方式,一种用yml配置
新建cloud-gateway-gateway9527模块
pom
不要引入spring web依赖,否则启动不了
<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
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
@SpringBootApplication
@EnableEurekaClient
public class GateWayMain9527 {
public static void main(String[] args) {
SpringApplication.run( GateWayMain9527.class,args);
}
}
新增网关配置
我们目前不想暴露8001端口,希望在8001外面套一层9527
给cloud-provider-payment8001的两个方法做路由映射
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注册中心
访问http://localhost:8001/payment/get/31
访问http://localhost:9527/payment/get/31,也能访问成功
访问http://localhost:9527/payment/lb
d
编码码配置网关路由
Gateway网关路由有两种配置方式,一种用编码配置
我们想通过9527网关访问到外网的百度新闻网址
配置类
编写配置类GateWayConfig
@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
实现动态路由
我们当前的路由映射是将地址写死了
而我们应该要达到的效果是同以前一样,通过访问微服务提供者的服务命调用所提供的服务,尽管这个微服务是一个集群。这些客户端都不关心,所以我们要配置GateWay通过微服务名实现动态路由。
yml
通过配置spring.cloud.gateway.discovery.locator.enabled开启从注册中心动态创建路由的功能,利用微服务名进行路由,默认false
此时的spring.cloud.gateway.routeslist集合中的uri属性值为lb://serviceNameuri的协议为lb,表示启用Gateway的负载均衡功能。serviceName时注册中心注册的名称
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
动态路由配置成功!
Predicate的使用
当我们启动的我们9527的时候会看见控制台输出
我们之前使用Predicate是属性名是predicates说明它能配置多个匹配条件,而我们目前只匹配了Path条件
Route Predicate Factorie
查看官网cloud.spring.io/spring-clou…
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
After Route Predicate Factory
请求时间满足在配置时间之后
这个时间怎么获得呢?
通过Java提供的ZonoeDateTime.now()获得当地的时间
After=时间 我们把时间改为自己当地的时间后一分钟进行测试
重新启动测试,访问http://localhost:9527/payment/get/31此时再配置时间之前。报错404
配置时间之后在访问,一切正常
同理Before Between也是一样的配置和使用
Cookie Route Predicate Factory
配置文件predicates加上Cookie
Cookie=username,kylin 只允许cookie键为username 值为kylin
通过命令行curl http://localhost:9527/payment/lb访问
不符合条件报错404
加上cookie访问curl http://localhost:9527/payment/lb --cookie "username=kylin"
访问成功!一切正常
Header Route Predicate Factory
Header=X-Request-Id, \d+ 请求头要有X-Request-Id属性并且值为整数的正则表达式
访问curl http://localhost:9527/payment/lb -H "X-Request-Id:123"值为整数,一切正常
值为负数curl http://localhost:9527/payment/lb -H "X-Request-Id:-123"
报错404,配置成功!
说白了,Predicate就是为了实现一组匹配规则,让请求过来找到对应的Route进行处理
Filter的使用
路由过滤器允许以某种方式修改传入的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
全局GlobalFilter
自定义全局过滤器
Gateway提供好的过滤器并没有太大的意义,我们可以自定义过滤器编写业务逻辑
将我们配置Predicate注释,编写MyLogGateWayFilter实现GlobalFilter, Ordered,判断是否带有uname参数不能为null
@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,访问不拦截
http://localhost:9527/payment/lb?uname=kylin加上uanme参数且值不为null
访问成功!