为什么需要Gateway
通用功能的抽取
前端在调用后端的服务时,往往都需要先通过一些通用的功能,比如跨域,权限校验,限流等。
如果没有Gateway,那么这些功能都需要在每个服务里单独实现一遍,那么就会有很多的重复代码。
地址的维护
如果没有Gateway,每一个微服务都需要在前端维护一个调用地址,如果有几百个微服务就有几百个地址,那么前端会非常痛苦。
有了Gateway就统一交给Gateway来管理,前端直接请求网关即可。
其他功能
什么是Gateway
Spring官方开发的,基于webflux + Netty + Reactor 实现的响应式API网关,不能运行在传统的servlet中,也不能构建成war包。
快速开始
- 在父项目中创建子项目
gateway
添加依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
</dependencies>
添加启动类 ```java package com.lang;
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }
4. 添加配置文件application.yml
```java
server:
port: 8088
Spring:
application:
name: api-gateway
cloud:
#gateway的配置
gateway:
#路由规则
routes:
- id: order_route #路由的唯一标识
uri: http://localhost:8010 #需要转发的地址
#断言规则 用于路由规则的匹配
predicates:
- Path=/order-serv/**
# http://localhost:8088/order-serv/order/add
# 路由到http://localhost:8010/order-serv/order/add
filters:
- StripPrefix=1
# 去除掉第一层路径order-serv,保证转发后的路径是正确的
# 即http://localhost:8010/order/add
Gateway整合Nacos
在上面的快速开始中,仍然手动维护了调用的地址,整合了Nacos后就不需要手动写死调用地址了。
引入依赖
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency>
修改配置文件 ```xml server: port: 8088 Spring: application: name: api-gateway cloud:
gateway的配置
gateway:
路由规则
routes:
- id: order_route #路由的唯一标识 uri: lb://order-service #需要转发的地址 lb就是loadbalance, 即使用nacos中的负载均衡策略 #断言规则 用于路由规则的匹配 predicates: - Path=/order-serv/** # http://localhost:8088/order-serv/order/add # 路由到http://localhost:8010/order-serv/order/add filters: - StripPrefix=1 # 去除掉第一层路径order-serv,保证转发后的路径是正确的 # 即http://localhost:8010/order/add
nacos: server-addr: 127.0.0.1:8848 discovery:
username: nacos password: nacos namespace: public
主要修改了:
- 添加了nacos的配置
- 将uri改成了服务名`lb://order-service`
3. 重启项目并访问原来的链接,发现可以正常访问。
于是,我们就完成了网关和Nacos的集成。
<a name="gKdxr"></a>
# 断言(predicates)详解
断言就是根据一定的规则,来确定要不要进行路由的转发,例如在上面的例子中:
```xml
predicates:
- Path=/order-serv/**
就表示,路径必须要符合xxxxx/order-serv/xxxx才会进行转发。
不同类型的断言方式称之为不同的断言工厂。包括内置的断言工厂和自定义的断言工厂。
基于时间的断言工厂
- 时间之前BeforeRoutePredicateFactory: 接收一个日期参数,判断请求日期是否早于指定日期
- 时间之间BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
- 时间之后AfterRoutePredicateFactory: 接收一个日期参数,判断请求日期是否晚于指定日期
基于远程地址的断言工厂
RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
基于Cookie的断言工厂
CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求
cookie是否具有给定名称且值与正则表达式匹配。
‐Cookie=chocolate, ch.
基于Method请求方法的断言工厂
MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
‐Method=GET
等等等等,具体可以看文档。
过滤器(Filter)详解
也有很多内置的过滤器。即在转发的时候,对请求进行一些操作,例如去掉第一级,添加头部信息,重定向等等等等。
全局过滤器
全局过滤器对所有路由生效,而且一旦定义了,不需要额外进行配置,即可投入使用。
自定义全局过滤器:
- 继承GlobalFilter;
- 重写方法;
- 添加Comonent注解;
访问时可以看到@Component public class LogGlobalFilter implements GlobalFilter { Logger logger = LoggerFactory.getLogger(this.getClass()); @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { logger.info(exchange.getRequest().getPath().value()); return chain.filter(exchange); } }
2021-10-08 20:16:21.395 INFO 27768 --- [ctor-http-nio-2] com.lang.filters.LogGlobalFilter : /order/add