1.概述
1.是什么
Gateway是在Spring生态系统之上构建的API网关服务,基于Spring5,Springboot2 和Project Reactor等技术。
Gateway旨在提供一种简单有效的方式在对API进行路由,以及提供一些强大的过滤器功能,如熔断、限流、重试等。
SpringCloud Gateway是基于WebFlux框架实现的,使用WebFlux中的reactor-netty响应式编程组件, 而WebFlux框架底层则使用了高性能的Reactor模式通信框架Netty。
2.能干嘛
反向代理、鉴权、流量控制、熔断、日志监控。
2.三大核心概念
Route(路由):路由是构建网关的基本模块,它由ID,目标URI,一系列的断言和过滤器组成,如断言为true则匹配该路由
Predicate(断言):参考的是Java8的java.util.function.Predicate
开发人员可以匹配HTTP请求中的所有内容(例如请求头或请求参数),如果请求与断言相匹配则进行路由。
Filter(过滤):指的是Spring框架中GatewayFilter的实例,使用过滤器,可以在请求被路由前或者之后对请求进行修改.
3.Gateway工作流程
核心逻辑:路由转发+执行过滤器链。
4.入门配置
1.新建Module
cloud-gateway-gateway49527
2.POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>dt-SpringCloud-2020</artifactId>
<groupId>com.dt.springcloud</groupId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-gateway-gateway9527</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<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>
<!--一般基础配置类-->
<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>
3.yml
server:
port: 49527
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/** # 断言,路径相匹配的进行路由
#服务注册Eureka配置
eureka:
client:
register-with-eureka: true #表示向注册中心注册自己 默认为true
fetch-registry: true #是否从EurekaServer抓取已有的注册信息,默认为true,单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 入驻集群版Eureka地址
# defaultZone: http://localhost:7001/eureka/ # 入驻单机版Eureka地址
instance:
instance-id: cloud-gateway-service # 服务名称
4.业务类:无
5.主启动类
package com.dt.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableEurekaClient
public class GateWayMain49527 {
public static void main(String[] args) {
SpringApplication.run(GateWayMain49527.class, args);
}
}
6.yml新增路由映射配置
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/** # 断言,路径相匹配的进行路由
7.测试
启动eureka7001、eureka7002
启动8001
启动49527
访问
添加网关前访问
http://localhost:8001/payment/get/1
添加网关后访问
http://localhost:49527/payment/get/1
8.Gateway网关路由有两种配置方式
1.配置文件
参照上面的步骤。
2.代码中注入RouteLocator的Bean
1.实例
通过9527网关访问到外网的百度新闻网址。
2.编码
增加config
package com.dt.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;
@Configuration
public class GateWayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder routeLocatorBuilder) {
RouteLocatorBuilder.Builder routers = routeLocatorBuilder.routes();
routers.route("path_route_dt", r -> r.path("/news").uri("http://news.baidu.com")).build();
return routers.build();
}
}
5. 通过微服务名实现动态路由
之前通过服务名称+ribbon实现负载轮询。
现在有了gateway之后,默认情况下Gateway会根据注册中心注册的服务列表,以注册中心上微服务名为路径创建动态路由进行转发,从而实现动态路由的功能。
1.启动
启动一个eureka7001、eureka7002 、两个服务提供者8001/8002
访问测试:http://localhost/consumer/diyLoadBalancedTest
该方式是通过在eureka上注册过的微服务名称结合Ribbon调用实现的轮询效果。
2.修改Gateway49527的yml配置
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 #通过loadbalance的方式,利用注册中心(如:Eureka)中的服务名称 匹配后提供服务的路由地址
# uri的协议为lb,表示启用Gateway的负载均衡功能。
#lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri
predicates:
- Path=/payment/get/** # 断言,路径相匹配的进行路由
- id: payment_routh2 #payment_route #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #通过loadbalance的方式,利用注册中心(如:Eureka)中的服务名称 匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** # 断言,路径相匹配的进行路由
3.说明
需要注意的是uri的协议为lb,表示启用Gateway的负载均衡功能。
lb://serviceName是spring cloud gateway在微服务中自动为我们创建的负载均衡uri
没用gateway之前实现负载思路:
http->80(注册中心 +ribbon+服务名称)
使用gateway之后实现负载思路:
http->gateway -> lb(通过负载均衡方式)->lb://serviceName(spring cloud gateway在微服务中自动为我们创建的负载均衡uri)
4.访问测试
http://localhost:49527/payment/lb/getServerPort
6.Predicate的使用
Spring Cloud Gateway将路由匹配作为Spring WebFlux HandlerMapping基础架构的一部分。Spring Cloud Gateway包括许多内置的Route Predicate工厂。所有这些Predicate都与HTTP请求的不同属性匹配。多个Route Predicate工厂可以进行组合。
Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。 Spring Cloud Gateway 包含许多内置的Route Predicate Factories。
所有这些谓词都匹配HTTP请求的不同属性。多种谓词工厂可以组合,并通过逻辑and。
1.常用的Route Predicate
After Route Predicate
after 路由谓词工厂采用一个参数,即日期时间。此谓词匹配在指定日期时间之后发生的请求。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- After=2023-06-25T15:30:24.699+08:00[Asia/Shanghai]
Before Route Predicate
before 路由谓词工厂采用一个参数 a datetime
。此谓词匹配在指定的 之前发生的请求datetime
。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Before=2023-06-25T15:30:24.699+08:00[Asia/Shanghai]
Between Route Predicate
路由谓词工厂之间有两个参数,datetime1
和datetime2
。此谓词匹配发生在 afterdatetime1
和 before的请求datetime2
。datetime2
参数必须在之后datetime1
。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Between=2023-05-25T15:30:24.699+08:00[Asia/Shanghai],2023-06-25T15:30:24.699+08:00[Asia/Shanghai]
Cookie Route Predicate
cookie 路由谓词工厂有两个参数,cookie 名称和正则表达式。此谓词匹配具有给定名称且其值与正则表达式匹配的 cookie。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Cookie=chocolate, ch
Header Route Predicate
标头路由谓词工厂有两个参数,标头名称和正则表达式。此谓词与具有给定名称且值与正则表达式匹配的标头匹配。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Header=X-Request-Id,\d+
Host Route Predicate
主机路由谓词工厂采用一个参数:主机名模式列表。该模式是一种 Ant 风格的模式,.
以分隔符为分隔符。此谓词匹配Host
与模式匹配的标头。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Host=**.somehost.org,**.anotherhost.org
Method Route Predicate
Method Route Predicate Factory 采用一个或多个参数:要匹配的 HTTP 方法。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Method=GET,POST
Path Route Predicate
Path Route Predicate Factory 有两个参数:一个 SpringPathMatcher
模式列表和一个名为 的可选标志matchOptionalTrailingSeparator
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/red/{segment},/blue/{segment}
Query Route Predicate
查询路由谓词工厂有两个参数:一个 requiredparam
和一个 optional regexp
。
- id: payment_routh3
uri: lb://cloud-payment-service
predicates:
- Path=/payment/lb/**
- Query=green
7.Filter的使用
1.Filter是什么
路由过滤器可用于修改进入的HTTP请求和返回的HTTP响应,路由过滤器只能指定路由进行使用。
Spring Cloud Gateway 内置了多种路由过滤器,他们都由GatewayFilter的工厂类来产生。
2.Filter的分类
- GatewayFilter:Spring Cloud Gateway 包含许多内置的 GatewayFilter 工厂。这个太多了,一般不用。
- GlobalFilter:全局过滤器。
3.自定义全局过滤器测试
实现两个接口:GlobalFilter,Ordered。
package com.dt.springcloud.filter;
import lombok.Data;
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.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Date;
/**
* 自定义Gateway Global Filter
*/@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter, Ordered {
/**
* 自定义过滤器逻辑:请求种必须带有uname参数,不带不进行正常的路由转发并返回自定义状态码
* @param exchange
* @param chain
* @return
*/ @Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
log.info("*******come in MyLogGatewayFilter:" + new Date());
String uname = exchange.getRequest().getQueryParams().getFirst("uname");
if (uname == null) {
log.info("**********用户名称为null,非法用户! ");
exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);//设置不允许进入响应。
return exchange.getResponse().setComplete(); //返回操作完成
}
return chain.filter(exchange);//将信息增加到调用链中 继续执行后续过滤器
}
/**
* 过滤器执行顺序, 数值越小优先执行。
*
* @return */ @Override
public int getOrder() {
return 0;
}
}
4.访问测试
http://localhost:49527/payment/lb/getServerPort?uname=1