# spring cloud gateway 实战技巧
# 使用 nacos 做服务注册
spring cloud 版本:2022.0.2 spring cloud albaba 版本:2022.0.0.0-RC1
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
// 要使用 lb 功能,就需要该库
implementation 'org.springframework.cloud:spring-cloud-loadbalancer'
implementation 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery'
2
3
4
# 网关端
spring:
application:
name: alto-gateway
profiles:
active: dev
config:
import: "optional:nacos:${spring.application.name}-${spring.profiles.active}.yml?refresh=true"
cloud:
# Nacos帮助文档: https://nacos.io/zh-cn/docs/v2/concepts.html
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 注册到 nacos 的指定 namespace,默认为 public
namespace: dev
group: DEFAULT_GROUP
gateway:
routes:
- id: app-demo
uri: lb://app-demo
predicates:
- Path=/app-demo/**
filters:
- StripPrefix=1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
WARNING
如果要使用 lb:// 功能需要至少满足两项:
- 依赖
spring-cloud-loadbalancer
- 开启服务发现
@EnableDiscoveryClient
package cn.mrcode.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class AltoGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(AltoGatewayApplication.class, args);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 服务端需要注意的
只需要注册到了服务中心,就可以被访问了
spring:
application:
name: app-demo
profiles:
active: dev
config:
import: "optional:nacos:${spring.application.name}-${spring.profiles.active}.yml?refresh=true"
cloud:
# Nacos帮助文档: https://nacos.io/zh-cn/docs/v2/concepts.html
nacos:
discovery:
server-addr: 127.0.0.1:8848
# 注册到 nacos 的指定 namespace,默认为 public
namespace: dev
group: DEFAULT_GROUP
2
3
4
5
6
7
8
9
10
11
12
13
14
15
WARNING
@EnableDiscoveryClient 是用来从注册中心获取服务列表的
# 一些技巧
# 全局过滤器生效问题
如果你实现了一个 GlobalFilter,并且交给了 IOC 容器,仅仅这样是不生效的 你访问的地址,匹配匹配一个路由规则,全局过滤器才会生效
@Bean
@Order
public RouteLocator routeLocator(RouteLocatorBuilder builder) {
return builder
.routes()
.route("auth", r -> r.path("/**").uri("http://127.0.0.1:11140"))
.build();
}
2
3
4
5
6
7
8
原因是它的工作流程如下图所示:
- 客户端访问一个地址
- 需要找到该地址对应的处理器映射,然后分发给处理器
- 再交给过滤器进行处理
# 自定义过滤器如何实现在配置文件中写过滤器器名
下面使用一个白名单功能的过滤器来说明
在 Spring Cloud Gateway 中,您可以使用 org.springframework.util.AntPathMatcher
工具类来匹配路径模式,用于自定义白名单路径。
下面是一个示例 过滤器工厂方法,为您提供了如何使用 AntPathMatcher
的示例:
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
@Component
public class WhiteListGatewayFilterFactory extends AbstractGatewayFilterFactory<WhiteListGatewayFilterFactory.Config> {
private AntPathMatcher pathMatcher = new AntPathMatcher();
public WhiteListGatewayFilterFactory() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerWebExchange mutableExchange = exchange.mutate();
String requestPath = exchange.getRequest().getPath().toString();
for (String whitePath : config.getWhiteList()) {
if (pathMatcher.match(whitePath, requestPath)) {
return chain.filter(mutableExchange).then();
}
}
mutableExchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return mutableExchange.getResponse().setComplete();
};
}
public static class Config {
private List<String> whiteList;
public Config() {
}
public List<String> getWhiteList() {
return whiteList;
}
public void setWhiteList(List<String> whiteList) {
this.whiteList = whiteList;
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
在上面的示例中,过滤器检查传入请求的路径是否匹配白名单列表中的任何路径。如果匹配,则放行请求,否则返回 HTTP 403 Forbidden 状态码。在 Config
类中,您可以将白名单路径列表作为配置属性进行指定。
您还需要在应用程序配置中声明该工厂类:
spring:
cloud:
gateway:
routes:
- id: my-route
uri: https://example.org
predicates:
- Path=/foo/**
filters:
- WhiteList= # 自定义的过滤器工厂类名
args:
whiteList: /foo/bar,/foo/baz # 配置白名单路径,使用逗号分隔
2
3
4
5
6
7
8
9
10
11
12
在上面的示例中,我们使用自定义的 WhiteList
过滤器(对应的是过滤器工厂 WhiteListGatewayFilterFactory),并将白名单路径 /foo/bar
和 /foo/baz
配置为 args
属性。自定义的过滤器工厂类名需与声明的名称相同。
# 过滤器中如何获取匹配的路由信息
想要在过滤器中获取到 route 相关信息,比如下面这个配置
spring:
cloud:
gateway:
routes:
- id: app-demo
uri: lb://app-demo
predicates:
- Path=/app-demo/**
filters:
- StripPrefix=1
2
3
4
5
6
7
8
9
10
想要找到匹配的 route.id 信息,可以如下做
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String routeId = (String)exchange.getAttribute("org.springframework.cloud.gateway.support.ServerWebExchangeUtils.gatewayPredicateMatchedPathRouteIdAttr");
2
3
这个是因为在 exchange 中有一个 attributes 的属性,该属性中有哪些信息如下所示
可能得使用场景:
- 自定义全局过滤器中,进行 token 验证,但是某些路径肯定是不需要验证的,没有登录也可以访问,所以就需要做一个白名单的,但是下游有很多服务,为了减少路径匹配次数,白名单按服务分类,在这里拿到对应的路由信息就可以进行放行
# 如何往下游服务传递 header
比如验证成功后,需要将 token 对应的用户 id 等信息传递给下游服务,就可以这样做
ServerHttpRequest newRequest = request.mutate()
.header("sso-user-id", jwtTokenInfo.getSub())
.build();
return chain.filter(exchange.mutate()
.request(newRequest)
.response(response)
.build());
2
3
4
5
6
7