介绍
在微服务项目中,各个功能模块拆分成了一个个微服务,每一个微服务都拥有自己的 ip 和端口。随着微服务逐渐增多时,客户端要去访问不同的服务,就要记住每个服务的 ip 和端口号,这在开发时简直就是灾难性的,混乱的。最终导致访问的入口不统一。
为了解决上面的问题,我们需要将客户端访问入口进行统一,于是 Spring Cloud Gateway 就出现了。
快速体验
新建一个项目或模块 Spring Cloud Gateway 的依赖如下(我自己在学习时有一个父模块):
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
自己在学习时,我已经建好一个 localhost:8011 的服务!
然后在 application.yml 中添加如下配置。
server:
port: 8888
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: order_route # 唯一标识路由
uri: http://localhost:8011 # 微服务的路由,当然也可以其它的服务
predicates: # 断言规则,用于路由的匹配
- Path=/order-serv/** # http://localhost:8011/order-serv/order/add
filters:
- StripPrefix=1 # 转发之前去掉第一层路径
其中,配置的一些信息如下。
- routes:配置路由信息
- id:路由唯一标识
- uri:服务的路径
- predicates:路由规则,用于路由的匹配,目前有以下的断言规则,后面会一一举出这些使用
- Path:路径匹配
- After:指定时间之后才能访问
- Before:指定时间之前才能访问
- Between:指定时间之间才能访问
- Header:指定的请求头才能访问
- Method:指定某个请求方法才能访问
- Query:必须携带某个参数才能访问
- filters:过滤器
- StripPrefix:转发之前去掉第几层的路径
尝试访问 http://localhost:8888/order-serv/order/add,可以正常地访问。
与 nacos 的整合
引入 nacos 的依赖,同时要排除 yaml 解析器的依赖,不然运行会出现异常。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</exclusion>
</exclusions>
</dependency>
当引入成功后,网关也是一个微服务了,此时可以通过服务名来访问了。
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: order_route # 唯一标识路由
uri: lb://order-service # lb的意思是,使用 nacos 中的 loadbalance 负载均衡器
同时 Spring Cloud Gateway 可以启动是否识别 nacos,这样就不用上面的写法了,但是据我了解上面的写法会比较多。
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true # 是否启动自动识别nacos服务
路由断言工厂
路由断言默认有以下几个:
- Path:路径匹配
- After:指定时间之后才能访问
- Before:指定时间之前才能访问
- Between:指定时间之间才能访问
- Header:指定的请求头才能访问
- Method:指定某个请求方法才能访问
- Query:必须携带某个参数才能访问
以上的规则可以一起使用,若全都不使用,则该服务下的所有路径都是可以访问到的。
Path
通配符
predicates:
- Path=/order-serv/**
占位符
predicates:
- Path=/order-serv/{path}
Before、After、Between
Between 是时间段,两个时间段之间需要用逗号隔开。不在规定的时间规则内访问,会返回 404 错误。
predicates:
- After=2022-11-30T14:50:49.088636500+08:00[Asia/Shanghai]
- Before=2022-11-30T14:55:00.088636500+08:00[Asia/Shanghai]
- Between=2022-11-30T15:00:00.088636500+08:00[Asia/Shanghai], 2022-11-30T15:05:00.088636500+08:00[Asia/Shanghai]
Header
请求头中没有该参数,会返回 404 错误。逗号后面为传递的值,可以是正则表达式,下面的例子是该参数的值必须要是长度 ≥1 的数字。
predicates:
- Header=X-Request-Id,\d+
Method
请求方法必须为 GET 请求,如果是其他的请求(比如 POST),会返回 404 错误。
predicates:
- Method=GET
Query
使用方法和 Header 类似,请求中没有携带该参数,会返回 404 错误。
predicates:
- Query=name, zhangsan|lisi
自定义断言工厂
自定义路由断言工厂需要继承 AbstractRoutePredicateFactory 类,重写apply方法的逻辑、在 apply 方法中可以通过 exchange.getRequest() 拿到 ServerHttpRequest 对象,从而可以获得请求的参数、请求方式、请求头等信息。
- 必须spring组件bean
- 类必须加上 RoutePredicateFactory 作为结尾
- 必须继承 AbstractRoutePredicateFactory
- 必须声明静态内部类声明属性来接收配置文件中的信息
- 需要结合 shortcutFieldOrder
示例
@Component
public class TokenRoutePredicateFactory extends AbstractRoutePredicateFactory<TokenRoutePredicateFactory.Config> {
public TokenRoutePredicateFactory() {
super(TokenRoutePredicateFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("token");
}
@Override
public Predicate<ServerWebExchange> apply(Config config) {
return (GatewayPredicate) serverWebExchange -> {
if(config.getToken().equals("bestguo2020")) {
return true;
}
return false;
};
}
@Validated
public static class Config {
private String token;
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
}
application.yml
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: order_route # 唯一标识路由
uri: lb://order-service # lb的意思是,使用 nacos 中的负载均衡器 http://localhost:8011
predicates: # 断言规则,用于路由的匹配
- Token=bestguo2020 # 注意类的名字,所以在配置时自定义断言的 key 为 Token
请勿发布违反中国大陆地区法律的言论,请勿人身攻击、谩骂、侮辱和煽动式的语言。