官网地址:https://docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html/
1.网关入门 helloword
网关不依赖start-web
导入的pom:
<!--gateway-->
<dependency>
<groupIdorg.springframework.cloud</groupId>
<artifactIdspring-cloud-starter-gateway</artifactId>
<exclusions>
<exclusion>
<groupIdorg.springframework.boot</groupId>
<artifactIdspring-boot-starter-web</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupIdcom.alibaba.cloud</groupId>
<artifactIdspring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 指标监控健康检查的actuator,网关是响应式编程删除掉spring-boot-starter-web dependency-->
<dependency>
<groupIdorg.springframework.boot</groupId>
<artifactIdspring-boot-starter-actuator</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupIdorg.projectlombok</groupId>
<artifactIdlombok</artifactId>
<version1.18.28</version>
<scopeprovided</scope>
配置文件:
server:
port: 8085
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
#路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
- id: order-service
#匹配后提供服务的路由地址
uri: http://localhost:8081/
#uri: http://cloud-payment-service #匹配后提供服务的路由地址
# 断言,路径相匹配的进行路由
predicates:
- Path=/order/getOrder
直接访问网关服务+网关端口-》
http://localhost:8085/order/getOrder
最后服务转发到8081服务对应的接口上
2.使用服务名的方式调用网关
正常我们会使用服务名的方式进行服务间的调用
不会使用端口号的形式,不然端口号的变更很难维护
变更配置文件
引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
变更配置文件
server:
port: 8085
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
#路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
- id: order-service
#匹配后提供服务的路由地址
uri: lb://order-service
#uri: http://cloud-payment-service #匹配后提供服务的路由地址
# 断言,路径相匹配的进行路由
predicates:
- Path=/order/getOrder
3.常用的内置Route Predicate
是什么?
Spring Cloud Gateway包含许多内置的路由谓词工厂。 所有这些谓词都匹配HTTP请求的不同属性。 您可以使用逻辑 and
语句来联合组合多个路由谓词工厂。
在gateway服务启动的时候会看到这样的日志
After,before....
Gateway 启动的时候会加载默认的谓词工厂
1.Predicate之After
配置文件变更:
server:
port: 8085
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
#路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
- id: order-service
#匹配后提供服务的路由地址
uri: lb://order-service
#uri: http://cloud-payment-service #匹配后提供服务的路由地址
# 断言,路径相匹配的进行路由
predicates:
- Path=/order/getOrder
- After=2023-07-07T22:14:00.583857100+08:00[Asia/Shanghai]
局部变更
- After=2023-07-07T22:14:00.583857100+08:00[Asia/Shanghai]
after用于限定请求的处理时间,只有在指定时间之后的请求才会被匹配并路由。给出的配置:
生成时间的方式:
public class DateUtil {
public static void main(String[] args) {
System.out.println(ZonedDateTime.now());
}
}
结果:2024-07-07T22:09:45.583857100+08:00[Asia/Shanghai]
应用场景:
举个例子:抢茅台,设置茅台开始抢购的时间
只有到该时间之后接口才会有效,否则一直404
4.Predicate之Cookie
包含cookie且值匹配
-
Cookie=username,zhangsan
配置如下:
server:
port: 8085
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
#路由的ID(类似mysql主键ID),没有固定规则但要求唯一,建议配合服务名
- id: order-service
#匹配后提供服务的路由地址
uri: lb://order-service
#uri: http://cloud-payment-service #匹配后提供服务的路由地址
# 断言,路径相匹配的进行路由
predicates:
- Path=/order/getOrder
- After=2024-07-07T22:14:00.583857100+08:00[Asia/Shanghai]
#- Before=2023-07-08T21:09:00.583857100+08:00[Asia/Shanghai]
- Cookie=username,zhangsan
精确匹配,匹配不到404
4.Predicate之Header
配置如下
predicates:
- Path=/order/getOrder
- After=2024-07-07T22:14:00.583857100+08:00[Asia/Shanghai]
#- Before=2023-07-08T21:09:00.583857100+08:00[Asia/Shanghai]
- Cookie=username,zhangsan
#- Header=X-Request-Id=123456 \d+ #请求头要有X-Request-Id且值正整数的正表达式
如果输入的是字符串404
- Host=**.css.com
请求头包含任意值后缀是css.com的域名
4.Predicate之Query Route 谓词工厂
指定请求里必须包含参数,允许正则表达式
-
- Query=username,\d+ 要有参数名username并且必须是整数
-
- RemoteAddr=192.168.124.1/24 # 外部访问我的ip限制,最大跨度不超过32,目前是1-24-
-
- Method=
4.自定义predicate
gateway的谓词断言和原生的写法很类似,照葫芦画瓢,参考源码。
新建一个自定义的路由断言工厂,格式和源码格式一样
参考After谓词 源码如下:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package org.springframework.cloud.gateway.handler.predicate;
import jakarta.validation.constraints.NotNull;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import org.springframework.web.server.ServerWebExchange;
public class AfterRoutePredicateFactory extends AbstractRoutePredicateFactory<AfterRoutePredicateFactory.Config> {
public static final String DATETIME_KEY = "datetime";
public AfterRoutePredicateFactory() {
super(AfterRoutePredicateFactory.Config.class);
}
public List<String> shortcutFieldOrder() {
return Collections.singletonList("datetime");
}
public Predicate<ServerWebExchange> apply(AfterRoutePredicateFactory.Config config) {
return new GatewayPredicate() {
public boolean test(ServerWebExchange serverWebExchange) {
ZonedDateTime now = ZonedDateTime.now();
return now.isAfter(config.getDatetime());
}
public Object getConfig() {
return config;
}
public String toString() {
return String.format("After: %s", config.getDatetime());
}
};
}
public static class Config {
@NotNull
private ZonedDateTime datetime;
public Config() {
}
public ZonedDateTime getDatetime() {
return this.datetime;
}
public void setDatetime(ZonedDateTime datetime) {
this.datetime = datetime;
}
}
}
Config 内部类对应yaml文件里的配置,咱们在配置After的时候使用的是
-
After=time.....
这里要变更成我们自己的pridicate这里的配置就可以按照我们自己定义的规则配置。
gateway支持两种配置方式
-
1.Shortcut Configuration
-
2.Fully Expanded Arguments
方式一最简单
比如
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- Cookie=mycookie,mycookievalue
方式二
写法参考下面这种方式
Args key value
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- name: Cookie
args:
name: mycookie
regexp: mycookievalue
官网地址:docs.spring.io/spring-cloud-gateway/docs/4.0.4/reference/html
假设业务场景:
有这样一个业务场景,请求参数里面必须包含一个参数为userType的参数,该参数代表着用户的会员等级,只有会员等级为gold的才可以访问。
代码实现
package com.css.tom.mypridicate;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.function.Predicate;
/**
* @author weiwensi
* @version 1.0-SNAPSHOT
* @since 2024/7/8 21:49
*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
public MyRoutePredicateFactory() {
super(MyRoutePredicateFactory.Config.class);
}
@Override
public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
return new Predicate<ServerWebExchange>() {
//serverWebExchange 这个参数 相当于servlet的request
@Override
public boolean test(ServerWebExchange serverWebExchange) {
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
if (userType == null) {
return false;
}
//如果说参数存在,就和Config进行比较
if(userType.equalsIgnoreCase(config.getUserType())){
return true;
}
return false;
}
};
}
//这个Config类就是我们的路断言规则,很重要
public class Config {
@Setter
@Getter
private String userType; //对应会员等级 /钻石,金牌,银牌
}
}
配置文件配置(Fully方式)
- name: My
args:
userType: diamond
如果使用shortcut的方式自定义实现代码里参考After的
public List<String> shortcutFieldOrder() {
return Collections.singletonList("datetime");
}
增加如下代码:
public List<String> shortcutFieldOrder() {
return Collections.singletonList("userType");
}
完整代码:
package com.css.tom.mypridicate;
import lombok.Getter;
import lombok.Setter;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
/**
* @author weiwensi
* @version 1.0-SNAPSHOT
* @since 2024/7/8 21:49
*/
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config> {
public MyRoutePredicateFactory() {
super(MyRoutePredicateFactory.Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Collections.singletonList("userType");
}
@Override
public Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config) {
return new Predicate<ServerWebExchange>() {
//serverWebExchange 这个参数 相当于servlet的request
@Override
public boolean test(ServerWebExchange serverWebExchange) {
String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");
if (userType == null) {
return false;
}
//如果说参数存在,就和Config进行比较
if(userType.equalsIgnoreCase(config.getUserType())){
return true;
}
return false;
}
};
}
//这个Config类就是我们的路断言规则,很重要
public class Config {
@Setter
@Getter
private String userType; //对应会员等级 /钻石,金牌,银牌
}
}
5.gateway过滤器
类型
-
全局默认过滤器 Global Filters
-
单一内置过滤器 GatewayFilter
-
自定义过滤器
官网地址:docs.spring.io/spring-cloud-gateway/docs/current/reference/html#global-filters
gateway内置过滤器
docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gatewayfilter-factories
38个 分组
-
RequestHeader 相关组
-
请求参数 Requestparameter 相关组
-
回应头 ResponseHeader 相关组
-
前缀和路径相关组
-
其他
配置文件配置