Gateway-网关服务
·
1. 引入依赖
新建网关模块, 启动类正常就行,不用加东西; 然后再pom.xml引入依赖
<!-- 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos 注册中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- 负载均衡器-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
2.配置路由规则
在spring.cloud.gateway.routes下配置路由规则;
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.10.128:8848
gateway:
routes:
- id: item-service
uri: lb://item-service
predicates:
- Path=/items/**,/search/**
# 仅在这个路径生效
filters:
- AddRequestHeader=aaa, ylz
# 这个配置对全部路径生效
default-filters:
- AddRequestHeader=all, hahahhaha
- id: 唯一id,一般用微服务名
- uri: 转发的目标地址, lb是负载均衡, 去nacos找服务地址
- predicates: 路由断言, 满足规则则转发, 里面有多种断言
| 断言名称 | 参数 | 作用 | 示例配置 | 说明 |
|---|---|---|---|---|
| After | 1 个,datetime(ZonedDateTime 格式) |
仅匹配指定时间之后的请求 | After=2025-09-03T10:00:00+08:00[Asia/Shanghai] |
只有指定时间之后的请求才会被路由 |
| Before | 1 个,datetime |
仅匹配指定时间之前的请求 | Before=2025-09-10T23:59:59+08:00[Asia/Shanghai] |
指定时间之前的请求会被路由 |
| Between | 2 个,均为datetime |
仅匹配两个指定时间区间内的请求 | Between=2025-09-03T00:00:00+08:00[Asia/Shanghai],2025-09-05T23:59:59+08:00[Asia/Shanghai] |
两个时间之间的请求会被路由 |
| Cookie | 2 个,Cookie 名、值正则 | 请求携带指定 Cookie 且值匹配正则 | Cookie=userToken,^[a-zA-Z0-9]{16}$ |
必须携带指定 Cookie 且值符合正则规则 |
| Header | 2 个,请求头名、值正则 | 请求包含指定请求头且值匹配正则 | Header=Content-Type,application/json |
请求头存在且值匹配时才路由 |
| Host | 多个,域名(支持通配符) | 匹配请求 Host 域名 | Host=api.example.com,*.test.com |
支持精确域名或通配符子域名匹配 |
| Method | 多个,HTTP 请求方式 | 匹配指定请求方法 | Method=POST,PUT |
仅匹配 GET/POST/PUT/DELETE 等指定请求方式 |
| Path | 路径规则列表、是否匹配末尾斜杠 | 匹配请求访问路径 | Path=/api/product/**,true |
支持*单通配、**多通配,可控制末尾斜杠匹配 |
| Query | 请求参数名、参数值正则(可选) | 校验请求 URL 查询参数 | Query=token / Query=age,\d+ |
可仅校验参数存在,也可校验参数值格式 |
| RemoteAddr | 多个 CIDR 格式 IP / 网段 | 匹配客户端真实请求 IP | RemoteAddr=192.168.1.0/24,10.0.0.5/32 |
支持单 IP 与整网段 IP 拦截匹配 |
| Weight | 分组名、权重数值 | 同路由分组按权重分流流量 | Weight=group1,8 / Weight=group1,2 |
同路由 ID 多服务配置,按权重比例分发请求 |
| XForwardedRemoteAddr | 多个 CIDR 格式 IP / 网段 | 解析代理转发真实客户端 IP 匹配 | XForwardedRemoteAddr=192.168.2.0/24 |
多级反向代理场景专用 IP 校验 |
- filters: 路由过滤器, 请求和响应经过时进行处理, 同样也有好几种参数
| 过滤器名称 | 作用 | 核心参数 | 示例配置 | 说明 / 适用场景 |
|---|---|---|---|---|
| AddRequestHeader | 为请求添加指定的请求头 | name, value |
AddRequestHeader=X-Request-Id, 12345 |
身份传递、环境标识;下游服务可读取该请求头 |
| AddResponseHeader | 为响应添加指定的响应头 | name, value |
AddResponseHeader=X-Response-From, gateway |
安全头、缓存控制;可标识响应经过网关处理 |
| RewritePath | 重写请求路径 | regexp, replacement |
RewritePath=/api/(?<segment>.*), /service/${segment} |
路径转换、版本控制;如 /api/user/1 → /service/user/1 |
| PrefixPath | 为请求路径添加前缀 | prefix |
PrefixPath=/api/v1 |
路径前缀追加;如 /hello → /api/v1/hello |
| StripPrefix | 移除路径中的指定前缀 | parts(整数) |
StripPrefix=1 |
API 版本管理;如 StripPrefix=1 时 /v1/user/1 → /user/1 |
| RedirectTo | 重定向请求 | status, url |
— | 路由跳转、维护页面 |
| SetPath | 直接设置请求路径 | template |
— | 简单固定路径重写定向 |
如果想要让过滤器处理全部的服务可以用 spring.cloud.gateway.default-filters, 配置项与spring.cloud.gateway.routes.filters一样
3. 自定义过滤器
虽然gateway提供的过滤器很多了, 但还是无法满足业务需求, 比如: 在网关统一校验登录状态; 此时就可以使用自定义过滤器
1.全局过滤器-GlobalFilter
@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {
// 类似netty的流水线, ServerWebExchange 是请求和响应的封装, GatewayFilterChain 是过滤器的链
// 返回值 Mono<Void> 表示异步处理,返回null表示处理完成
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 将处理好的exchange传给下一个过滤器
System.out.println("MyGlobalFilter: "+ exchange.getRequest().getPath());
return chain.filter(exchange);
}
// 优先级,数字越小优先级越高(可选)
@Override
public int getOrder() {
return 0;
}
}
- 用@Component成为bean
- 实现GlobalFilter接口, 实现Ordered接口(可选, 非必须)
- 实现filter方法, 拿到exchange(封装了请求和响应, 这里也可以说是过滤器的上下文), 可以进行处理, 比如校验token; 处理完后用chain(过滤器链)调用下一个过滤器,将上下文exchange传过去
- 如果有实现Ordered接口, 就需要实现其getOrder方法, 返回的值越小优先执行
2. 路由过滤器-GatewayFilter
这种过滤器会读取你的配置来定制过滤器, 因此它得是工厂类
无参配置
spring:
cloud:
gateway:
routes:
- id: item-service
uri: lb://item-service
predicates:
- Path=/items/**,/search/**
filters:
- Aaa
default-filters:
- Aaa
这里配置项是Aaa, 在创建过滤器工厂类时的命名也有讲究, 应该是:
{ 配置项 }GatewayFilterFactory, 然后继承抽象类AbstractGatewayFilterFactory<Object>
@Component
public class AaaGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
@Override
public GatewayFilter apply(Object config) {
// 这样子没法指定顺序, 匿名内部类不能再实现Ordered接口
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("============路由过滤器: " + exchange.getRequest().getPath());
return chain.filter(exchange);
}
};
}
}
实现其apply方法返回GatewayFilter的实现类, 一般我们直接用匿名内部类去写就行; 但这样又没办法实现Ordered让过滤器优先执行, 这时可以如下:
@Override
public GatewayFilter apply(Object config){
// 用一个装饰器对象 OrderedGatewayFilter, 传入一个 GatewayFilter 和一个顺序值
return new OrderedGatewayFilter(new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("============路由过滤器: " + exchange.getRequest().getPath());
return chain.filter(exchange);
}
}, 1);
}
用一个装饰器对象OrderedGatewayFilter, 传入GatewayFilter实现类和排序值, 就能调整过滤器顺序
有参配置
如果我们的配置需要传参数, 就需要这样做
default-filters:
- Bbb=hello,ylz,hahaha
@Component
public class BbbGatewayFilterFactory extends AbstractGatewayFilterFactory<BbbGatewayFilterFactory.Config> {
@Override
public GatewayFilter apply(Config config) {
return new OrderedGatewayFilter(new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("============有参数的路由过滤器: 参数有: " + config.getA() + " " + config.getB() + " " + config.getC());
return chain.filter(exchange);
}
}, 2);
}
@Data
public static class Config {
private String a;
private String b;
private String c;
}
public BbbGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return List.of("a", "b", "c");
}
- 创建一个内部静态类Config, 会用它接受参数, 有几个参数就有多少成员变量
- 创建工厂类的无参构造器, 给父类传入Config类的字节码, 再把AbstractGatewayFilterFactory<Object>的泛型改成那个Config类AbstractGatewayFilterFactory<BbbGatewayFilterFactory.Config>
- 还需要实现shortcutFieldOrder方法, 返回列表, 列表中的元素是Config的成员名, 且顺序将会是接受配置的参数顺序(第一个对配置参数的第一个, 第二个对配置参数的第二个)

4. 实战示例: 获取登录用户信息, 转发到下游
@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final JwtTool jwtTool;
private static final String AUTHORIZATION = "authorization";
// spring mvc的匹配器,可以校验路径
private static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();
// 类似netty的流水线, ServerWebExchange 是请求和响应的封装, GatewayFilterChain 是过滤器的链
// 返回值 Mono<Void> 表示异步处理,返回null表示处理完成
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (isExculde(request.getPath().value())){
return chain.filter(exchange);
}
String token = null;
List<String> list = request.getHeaders().get(AUTHORIZATION);
if (list != null && !list.isEmpty()){
token = list.getFirst();
}
// 验证token
Long userId = null;
try {
userId = jwtTool.parseToken(token);
} catch (Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.UNAUTHORIZED);
// setComplete() 到这里就响应回去
return response.setComplete();
}
String userStr = userId.toString();
// mutate() 修改上下文, 最终返回新的exchange, 需要把新的王下传
ServerWebExchange newExchange = exchange.mutate()
.request(a -> a.header("userId", userStr))
.build();
// 将新的exchange传给下一个过滤器
return chain.filter(newExchange);
}
private boolean isExculde(String value) {
for (String path : authProperties.getExcludePaths()){
// match(), 校验路径
if (PATH_MATCHER.match(path, value)){
return true;
}
}
return false;
}
// 优先级,数字越小优先级越高(可选)
@Override
public int getOrder() {
return 0;
}
}
注意这里使用 exchange.mutate() .request(a -> a.header("userId", userStr)) .build(); 返回的是新的exchange, 要将其传递给下个过滤器
更多推荐


所有评论(0)