目录
Spring Cloud Gateway 学习专栏
1. Spring Cloud : Gateway 服务网关认识(一)
2. Spring Cloud :整合Gateway 学习 (二)
3. Spring Cloud:Gateway 路由定义定位器 RouteDefinitionLocator (三)
4. Spring Cloud : Gateway 网关过滤器 GatewayFilter(四)
5. Spring Cloud : Gateway 网关限流(五)
6. Spring Cloud:Gateway 集成 Sentinel (六)
7. Spring Cloud : Gateway Redis动态路由 (七)
8. Spring Cloud : Gateway 整合Swagger (八)
如果发现本文有错误的地方,请大家毫不吝啬,多多指教,欢迎大家评论,谢谢!
一、概述
本篇文章为系列文章,未读第一集的同学请猛戳这里: Spring Cloud : Gateway 服务网关认识 (一),对 Gateway 有了一些解,这篇文章开始撸起袖子整合 Spring Cloud Aibaba 整合 Gateway
二、SpringCloud 整合 Gateway
项目 model 结构
序号 | 项目名称 | 端口号 |
1 | mall-gateway (父项目) | |
2 | user-service | 8200 |
3 | product-service | 8300 |
4 | api-gateway | 9000 |
1. mall-gateway 公共依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<artifactId>mall-gateway</artifactId>
<groupId>com.zlp</groupId>
<version>1.0</version>
<packaging>pom</packaging>
<description>Demo project for Spring Boot</description>
<modules>
<module>user-service</module>
<module>api-gateway</module>
<module>product-service</module>
</modules>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-cloud-alibaba.version>2.1.0.RELEASE</spring-cloud-alibaba.version>
</properties>
<!-- 项目依赖管理 父项目只是声明依赖,子项目需要写明需要的依赖(可以省略版本信息) -->
<dependencyManagement>
<dependencies>
<!-- spring cloud 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring cloud alibaba 依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2. 创建一个 user-service 服务提供者
1. 添加依赖
<?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>
<groupId>com.zlp</groupId>
<artifactId>mall-gateway</artifactId>
<version>1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-service</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<dependencies>
<!--SpringBoot通用依赖模块-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>compile</scope>
</dependency>
<!--整合Knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 服务注册/发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>20.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. yml配置
把我 api-user 服务注册到Nacos
server:
port: 8200
spring:
application:
name: api-user
## nacos注册中心
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
3. UserController 控制层
@RestController
@RequestMapping("user")
@Api(value = "用户模块", tags = "用户模块")
public class UserController {
@GetMapping("{userId}")
@ApiOperation(value = "获取用户根据用户ID", notes = "获取用户根据用户ID")
public String getUserById(@PathVariable ("userId") Long userId) {
return "getUser===>" +String.valueOf(userId);
}
}
4. 启动服务 user-service
进入swagger http://127.0.0.1:8200/doc.html 调试 如图
3. 创建一个 mall-gateway 服务网关
1. 添加依赖
<?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">
<modelVersion>4.0.0</modelVersion>
<artifactId>api-getway</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<parent>
<groupId>com.zlp</groupId>
<artifactId>mall-gateway</artifactId>
<version>1.0</version>
</parent>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR3</spring-cloud.version>
<spring.cloud.alibaba.version>2.1.0.RELEASE</spring.cloud.alibaba.version>
<knife4j.version>2.0.4</knife4j.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--整合Knife4j-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 服务注册/发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.10.1</version>
</dependency>
<!-- sentinel提供的gataway适配器 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
<!--sentinel依赖包-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<!--sentinel限流规则持久化 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.6.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2. yml配置
server:
port: 9000
service-url:
user-service: http://localhost:8200
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
# 断言,路径相匹配的进行路由 (谓词)
- Path=/user/** # 路径匹配
三、路由规则
Spring Cloud Gateway 创建 Route 对象时, 使用 RoutePredicateFactory 创建 Predicate 对象,Predicate 对象可以赋值给 Route。
- Spring Cloud Gateway 包含许多内置的 Route Predicate Factories。
- 所有这些断言都匹配 HTTP 请求的不同属性。
- 多个 Route Predicate Factories 可以通过逻辑与(and)结合起来一起使用。
路由断言工厂 RoutePredicateFactory 包含的主要实现类如图所示,包括 Datetime、 请求的远端地址、 路由权重、 请求头、 Host 地址、 请求方法、 请求路径和请求参数等类型的路由断言。
1. Path 路径匹配
在getaway配置文件中添加 Path
规则:
当我们请求地址 http://127.0.0.1:9000/user/user/1
以 user 为条件匹配,如果请求路径符合规则,则放行
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
# 断言,路径相匹配的进行路由 (谓词)
- Path=/user/** # 路径匹配
测试结果
请求 http://127.0.0.1:9000/user/getUserInfo?userId=1 将会路由至 http://127.0.0.1:8200/user/getUserInfo?userId=1
输出结果
{"id":1,"username":"Zou.LiPing","nickname":"change","createTime":"2021-04-25 05:16:17","roleName":"超级管理员"}
2. 时间断言
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
- After=2021-04-16T16:30:00+08:00[Asia/Shanghai] # 在指定时间之后的请求会匹配该路由
如果当前时间小于配置时间 - After=2021-04-16T16:30:00+08:00[Asia/Shanghai] 请求会报404,如图
- [Asia/Shanghai] 代表地区
请求URL http://127.0.0.1:9000/user/getUserInfo?userId=1
3. Query 断言
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
- Query=token,^[0-9]*$ # 可以指定参数和值 ?name=数字 才允许访问
Query=token
:比如,http://127.0.0.1:9000/member/getUserInfo?userId=1&token=123
4. Method断言
当我们请求方法是Post 则报错
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
- Method=GET # 必须是Get才可以访问
- 必须是 Get 请求方式 http://127.0.0.1:9000/member/getUserInfo?userId=1
5. RemoteAddr
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
- RemoteAddr=192.168.10.1/0 # 匹配远程地址请求是 RemoteAddr 的请求,0表示子网掩码
RemoteAddr=192.168.10.1/0
:比如:http://127.0.0.1:9000/member/getUserInfo?userId=1
6. Header
spring:
application:
name: mall-gateway
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
# 匹配请求头包含 X-Request-Id 并且其值匹配正则表达式 \d+ 的请求
- Header=X-Request-Id, \d+
Postman 请求
7. 自定义路由断言
配置自定义断言工厂
/**
* 自定义路由断言工厂 <br/>
* <p>命名需要以RoutePredicateFactory结尾 比aRoutePredicateFactory 那么yml在使用时a就是断言工厂的名字</p>
* @date: 2021/4/16 14:07
*/
@Slf4j
@Component
public class CheckAuthRoutePredicateFactory extends AbstractRoutePredicateFactory<CheckAuthRoutePredicateFactory.User> {
public CheckAuthRoutePredicateFactory() {
super(User.class);
}
/**
* 自定义配置类
* @param config
* @date: 2021/4/16 14:04
* @return: java.util.function.Predicate<org.springframework.web.server.ServerWebExchange>
*/
@Override
public Predicate<ServerWebExchange> apply(User config) {
return exchange -> {
log.info("进入apply:name={}" ,config.getName());
if (config.getName().equals("kitty")) {
return true;
}
return false;
};
}
public static class User{
@Setter
@Getter
private String name;
}
}
predicates:
# 断言,路径相匹配的进行路由 (谓词)
- Path=/user/** # 路径匹配
# - After=2021-04-16T16:30:00+08:00[Asia/Shanghai] # 在指定时间之后的请求会匹配该路由
# - Query=userId,^[0-9]*$ # 可以指定参数和值 ?name=数字 才允许访问
# - Method=GET # 必须是Get才可以访问
- name: CheckAuth # 自定义断言工厂
args:
name: kitty
四、动态加载路由
动态路由其实就是面向服务的路由,Spring Cloud Gateway 支持与 Nacos 整合开发,根据 serviceId 自动从注册中心获取服务地址并转发请求,这样做的好处不仅可以通过单个端点来访问应用的所有服务,而且在添加或移除服务实例时不用修改 Gateway 的路由配置。
1. 添加依赖
<!-- 服务注册/发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2. 配置文件
server:
port: 9000
service-url:
user-service: http://localhost:8200
spring:
application:
name: mall-gateway
main:
allow-bean-definition-overriding: true
## redis配置
redis:
database: 0
host: 47.103.20.21
password: zlp123456
port: 6379
timeout: 7000
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
## gateway配置
gateway:
routes:
- id: user #路由的ID 保证唯一
uri: ${service-url.user-service} # 目标服务地址:uri以lb://开头(lb代表从注册中心获取服务),后面就是需要转发到的服务名称
predicates:
# 断言,路径相匹配的进行路由 (谓词)
- Path=/user/** # 路径匹配
- id: product
uri: lb://api-product
predicates:
- Path=/product/**
我们通过注册中心来解析我们当前服务地址获取URL
启动 product-service 服务
http://127.0.0.1:9000/product/getProduct?productId=1
3. 动态加载所有路由服务
即使配置了动态获取 URI 的方式,项目中微服务一旦过多几十上百个时,配置中仍然要写很多配置,这时候就可以使用服务名称转发,与服务发现组件进行结合,通过 serviceId
转发到具体服务实例。默认匹配URL /微服务名称/**
路由到具体微服务。
配置文件
server:
port: 9000
service-url:
user-service: http://localhost:8200
spring:
application:
name: mall-gateway
main:
allow-bean-definition-overriding: true
## redis配置
redis:
database: 0
host: 47.103.20.21
password: zlp123456
port: 6379
timeout: 7000
cloud:
## nacos注册中心
nacos:
discovery:
server-addr: 47.103.20.21:8848
## gateway配置
gateway:
discovery:
locator:
# 开启自动代理 (自动装载从配置中心serviceId)
enabled: true
# 服务id为true --> 这样小写服务就可访问了
lower-case-service-id: true
# # http://127.0.0.1:9000/api-user/user/getUserInfo?userId=1
http://127.0.0.1:9000/api-user/user/getUserInfo?userId=1
源码地址
mall-gateway 这个项目
https://gitee.com/gaibianzlp/zlp-mall-demo.git
参考链接
1. Spring-Cloud-Gateway之过滤器GatewayFilter
2. Spring Cloud Gateway(十):网关过滤器工厂 GatewayFilterFactory
3. Spring Cloud 系列之 Gateway 服务网关(二)
点关注不迷路,觉得对你有帮助请给一个赞或者长按一键三连,谢谢!