1. 什么是网关?网关有什么用?
在微服务架构中,网关就是一个提供统一访问地址的组件,它解决了内部微服务与外部的交互问题。网关主要负责流量的路由和转发,将外部请求引到对应的微服务实例上。同时提供身份认证、授权、限流、监控以及日志记录等功能。
从上图就能看出网关的作用了,它就是充当客户端与内部微服务之间的桥梁的。前端虽然可以发送ajax,但是它没有健康检测、没有负载均衡,所以需要使用网关来充当一个统一的入口。当前端的请求来到了网关,网关再去分发,因为网关是用 Java 代码来写的,所以可以在网关这里引入Nacos进行健康检测,引入LoadBalancer进行负载均衡。而且它还有超时重试等高级功能。
🍁网关的主要作用
- 提供统一的访问入口点:网关作为唯一的网络流量入口和出口,简化了客户端的访问。
- 安全控制:网关能够提供安全检查,例如统一登录和授权。
- 协议转换:网关可以在不同网络协议之间转换数据,例如处理HTTPS和HTTP之间的转换。
- 网络地址的转换:它允许局域网内的多个设备共享一个公共IP地址与外部网络通信,这样做可以提高安全性,节省IP地址,并使内部网络结构对外部不可见。
- 数据的过滤和处理:网关可以对流经的数据进行过滤和必要的处理。
2. Spring Cloud Gateway 的基础使用
2.1 Spring Cloud Gateway 的组成
- 路由:定义访问的目标地址。
- 断言:定义一组规则,让匹配到当前路由的请求去调用某个目标。
- 过滤器:对请求进行特殊处理。
2.2 Spring Cloud Gateway 最基础的使用
准备工作:
- 创建SpringBoot多模块项目
- 创建三个模块:网关、订单、用户
假设订单、用户模块在内网中,不能直接访问,需要通过网关路由到对应的服务上面。
准备相关模块中的 controller:
@RestController
@RequestMapping("/order")
public class OrderController {
@RequestMapping("/getcount")
public int getCount() {
return new Random().nextInt(1000);
}
}
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private ServletWebServerApplicationContext context; // 获取动态端口
@RequestMapping("/getname")
public String getName() {
return context.getWebServer().getPort() +
"--UserService:name=java-"+
new Random().nextInt(100);
}
}
以上两个某块只需要添加 Spring Web 依赖即可。
使用网关又分为两步:
- 添加依赖
- 配置规则
1. 添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
将其添加到网关模块中,不能添加到父模块中,因为 Spring Cloud Gateway 底层是响应式的 Reactor Web。(会冲突)
2. 配置路由规则
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090 # 路由
predicates: # 断言
- Path=/user/** // 满足断言,就会去走对应的路由
- id: orderservice
uri: http://localhost:9091
predicates:
- Path=/order/**
server:
port: 10086
在实际业务中,路由 uri 这里肯定不能直接写死,但是此处主要演示最基础的使用。
完成以上两步之后,运行订单服务、用户服务,网关,使用10086端口去访问两个内网中的服务,都能访问的到,这样就实现了统一入口!
2.3 单服务中的多路径配置
在上述示例中,每个服务只有一个controller,所以在配置网关路由规则的时候,直接写就行了,假如说,单个服务中有多个controller呢?路由规则该如何去写?
在user-service模块中创建日志controller:
@RestController
@RequestMapping("/userlog")
public class UserLogController {
@RequestMapping("/getlog")
public String getLog() {
return "UserLogService:log=java-"+
new Random().nextInt(1000);
}
}
多路径配置:
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090 # 路由
predicates: # 断言
- Path=/user/**,/userlog/getlog # 单服务多路径配置
- id: orderservice
uri: http://localhost:9091
predicates:
- Path=/order/**
server:
port: 10086
如果需要在单服务中完成多路径配置,那么这个时候只需要在Path后面写多个匹配规则,用英文的逗号隔开即可。不能在predicates下面在搞一个Path,因为同一个predicates下面不能出现相同类型的断言。
2.4 更多的断言类型
1.根据时间匹配 (3种类型)
- After:请求在指定时间之后才匹配。
- Before:请求在指定时间之前才匹配。
- Between:请求在指定时间中间才匹配。
2. Cookie:配置请求中的 Cookie 值。
3. Header:配置请求中的 Header 值。
4. Host:配置请求头中的 Host 值。
5. Method:匹配请求头中 Method 的值。
6. Path:匹配请求路径。
7. Query:匹配请求参数。
8. RemoteAddr:匹配请求的 IP 地址,支持 IPV4 和 IPV6.
9. Weight:根据权重来分发请求,权重根据 group 来计算。
10. XForwardedRemoteAddr:根据 X-Forwarded-For 匹配。
参考官方文档:https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
【示例】演示 Header
spring:
cloud:
gateway:
routes:
- id: userservice
uri: http://localhost:9090 # 路由
predicates: # 断言
- Path=/user/**,/userlog/getlog # 单服务多路径配置
- Header=X-Header-Flag, \d+
server:
port: 10086
使用 postman 构造 header:
① 正常访问
② 异常访问
上述例子中,”X-Header-Flag“ 表示 Header 中的 key,”\d+“ 是一个正则表达式,表示 key 的值,此处表示匹配 1 个或多个数字,才能访问的到。
其他正则表达式:
- \w+:匹配一个或多个字母、数字、下划线字符。
- \s+:匹配一个或多个空白字符(空格、制表符、换行符)。
- .*:匹配任意字符0次或多次。
- .+:匹配除了换行符之外的任意字符一次或多次。
- [abc]:匹配字符集中的任意一个字符,例如 [abc] 可以匹配 a、b、或 c。
- [^abc]:匹配除了字符集中的任意字符之外的任意字符。
- ^:匹配字符串的开始位置。
- &:匹配字符串的结束位置。
- |:用于匹配多个模式中的任意一个。
- ():用于分组,,可以将一组字符作为一个整体进行匹配。