⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.iocoder.cn/Spring-Cloud/Netflix-Zuul/ 「芋道源码」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

1. 概述

Zuul 是由 Netflix 开源的微服务网关,提供都动态路由、监控、熔断、安全等等功能。

Zuul is a gateway service that provides dynamic routing, monitoring, resiliency, security, and more.

Spring Cloud Netflix Zuul 将 Zuul 融入 Spring Cloud 生态体系,作为 Spring Cloud 微服务架构中的 API 网关。如下图所示:

Spring Cloud Netflix Zuul 代码

拓展小知识:

Zuul 有 1.X 和 2.X 两个版本,前者基于同步阻塞模式的编程模型实现,后者基于异步非阻塞模式的编程模型实现。两者的对比,可以看看[《Zuul1 和 Zuul2 该如何选择?》](https://blog.csdn.net/yang75108/article/details/86991401 TODO)文章。

目前,Spring Cloud Netflix Zuul 采用的是 Zuul 1.X 版本。并且,Zuul 2.X 不会被集成到 Spring Cloud 中,具体可见 ISSUE#86

可能因为 Spring Cloud 团队已经开源了 Spring Cloud Gateway 网关,而它和 Zuul 2.X 一样,也是基于异步非阻塞模式的编程模型实现。

所以胖友如果是新学 Spring Cloud 网关相关的内容,建议优先选择《芋道 Spring Cloud 网关 Spring Cloud Gateway 入门》

2. 为什么使用网关?

胖友可以后续阅读如下文章:

🙂 先继续 Zuul 的入门。

3. 快速入门

示例代码对应仓库:labx-21-sc-zuul-demo01

本小节我们来对 Zuul 进行快速入门。创建一个 labx-21-sc-zuul-demo01 项目,最终项目结构如下图:

 项目

3.1 引入依赖

创建 pom.xml 文件中,主要引入 Spring Cloud Gateway 相关依赖。代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>labx-21</artifactId>
<groupId>cn.iocoder.springboot.labs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>labx-21-sc-zuul-demo01</artifactId>

<properties>
<spring.boot.version>2.2.4.RELEASE</spring.boot.version>
<spring.cloud.version>Hoxton.SR1</spring.cloud.version>
<spring.cloud.alibaba.version>2.2.0.RELEASE</spring.cloud.alibaba.version>
</properties>

<!--
引入 Spring Boot、Spring Cloud、Spring Cloud Alibaba 三者 BOM 文件,进行依赖版本的管理,防止不兼容。
在 https://dwz.cn/mcLIfNKt 文章中,Spring Cloud Alibaba 开发团队推荐了三者的依赖关系
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- 引入 Spring Cloud Zuul 相关依赖,使用它作为网关,并实现对其的自动配置 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>

</project>

spring-cloud-starter-netflix-zuul 依赖中,会引入 Zuul 1.X 等等依赖,如下图所示:

 依赖

3.2 配置文件

创建 application.yaml 配置文件,添加 Spring Cloud Zuul 相关配置。配置如下:

server:
port: 8888

spring:
application:
name: zuul-application

# Zuul 配置项,对应 ZuulProperties 配置类
zuul:
servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul
# 路由配置项,对应 ZuulRoute 数组
routes:
route_yudaoyuanma:
path: /blog/**
url: http://www.iocoder.cn
route_oschina:
path: /oschina/**
url: https://www.oschina.net

server.port 配置项,设置网关的服务器端口。

zuul 配置项,Spring Cloud Zuul 配置项,对应 ZuulProperties 类。

servlet-path 配置项,设置 ZuulServlet 匹配的路径,默认为 /zuul。Zuul 和 SpringMVC 一样,都是通过实现自定义的 Servlet,从而进行请求的转发。如下图所示:

ZuulServlet

routes 配置项,对应 ZuulRoute Map。其中 key 为路由编号,value 为路由具体配置:

  • path:匹配的 URL 地址。
  • url:转发的 URL 地址。

这里,我们将以 /blog/** 开头的 URL 转发到 http://www.iocoder.cn,以 /oschina/** 开头的 URL 转发到 https://www.oschina.net

3.3 ZuulApplication

创建 ZuulApplication 类,网关的启动类。代码如下:

@SpringBootApplication
@EnableZuulProxy // 开启 Zuul 网关
public class ZuulApplication {

public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}

}

在类上,添加 @EnableZuulProxy 注解,声明开启 Zuul 网关功能。

3.4 简单测试

① 使用 ZuulApplication 启动网关。可以看到控制台打印 Spring Cloud Zuul 相关日志如下:

2020-05-03 18:16:26.568  INFO 44488 --- [           main] o.s.c.n.zuul.ZuulFilterInitializer       : Starting filter initializer

② 使用浏览器,访问 http://127.0.0.1:8888/blog,成功转发到目标 URI http://www.iocoder.cn,如下图所示:http://www.iocoder.cn

③ 使用浏览器,访问 http://127.0.0.1:8888/oschina,成功转发到目标 URI http://www.oschina.net,如下图所示:http://www.oschina.net

4. 基于注册中心实现动态路由

示例代码对应仓库:

「3. 快速入门」小节,我们在配置文件中,通过 path + url 的组合,添加了两个路由信息,这种我们一般称之为“静态路由”或者“传统路由”。

本小节,我们将通过 path + service-id 的组合,添加路由信息,这种我们一般称之为“动态路由”。如此,每个路由转发的 URL 地址,将从 Spring Cloud 注册中心获取对应 service-id 服务名对应的服务实例列表,并通过 Ribbon 等等进行负载均衡

我们直接从「3. 快速入门」小节的 labx-21-sc-zuul-demo01 项目来复制,搭建 Zuul 基于注册中心实现动态路由的示例。最终项目结构如下图:

 项目

分割线:先进行网关项目的改造。

4.1 引入依赖

修改 pom.xml 文件,引入注册中心 Nacos 相关的依赖如下:

<!-- 引入 Spring Cloud Alibaba Nacos Discovery 相关依赖,将 Nacos 作为注册中心,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

考虑到 Nacos 作为 Spring Cloud 架构中的注册中心,已经越来越流行了,所以本小节我们使用它。感兴趣的胖友,可以后面看看艿艿写的《芋道 Spring Cloud Alibaba 注册中心 Nacos 入门》文章。

友情提示:如果胖友想用使用 Eureka 作为注册中心,可以引入 spring-cloud-starter-netflix-eureka-client 依赖。

4.2 配置文件

修改 application.yaml 配置文件,增加注册中心相关的配置项。完整配置如下:

server:
port: 8888

spring:
application:
name: zuul-application

cloud:
nacos:
# Nacos 作为注册中心的配置项
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址

# Zuul 配置项,对应 ZuulProperties 配置类
zuul:
servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul
# 路由配置项,对应 ZuulRoute Map
routes:
route_yudaoyuanma:
path: /blog/**
url: http://www.iocoder.cn
route_oschina:
path: /oschina/**
url: https://www.oschina.net
route_users:
path: /users/**
service-id: user-service

spring.cloud.nacos.discovery 配置项,使用 Nacos 作为 Spring Cloud 注册中心的配置项。这里就不详细解释,毕竟 Nacos 不是主角。

② 在 zuul.routes 配置项中,添加“动态路由route_users,通过 service-id 配置路由对应 user-service 用户服务。

4.3 搭建用户服务

创建 labx-21-sc-user-service 项目,作为 user-service 用户服务。代码比较简单,艿艿就不瞎哔哔了。最终项目如下图所示:

4.4 简单测试

① 执行 UserServiceApplication 两次,启动两个 user-service 服务。启动完成后,在 Nacos 注册中心可以看到该服务的两个实例,如下图所示:Nacos  服务

② 执行 ZuulApplication 启动网关。

③ 访问 http://127.0.0.1:8888/users/user/get?id=1 地址,返回 JSON 结果如下:

{
"id": 1,
"name": "没有昵称:1",
"gender": 2
}

请求经过网关后,转发到 user-service 服务成功。


另外,Spring Cloud Zuul 集成 Spring Cloud 注册中心时,会给注册中心的每个服务在 Zuul 中自动创建对应的“动态路由”。例如说本小节的示例,对应配置文件的效果如下:

zuul:
routes:
user-service:
path: /user-service/**
service-id: user-service

我们来简单测试下,访问 http://127.0.0.1:8888/user-service/user/get?id=1 地址,返回 JSON 结果如下:

{
"id": 1,
"name": "没有昵称:1",
"gender": 2
}

友情提示:Zuul 通过 RibbonRoutingFilter 过滤器,使用 Ribbon 负载均衡请求后端的服务实例。

更多关于 Ribbon 的内容,胖友可以阅读《芋道 Spring Cloud Netflix 负载均衡 Ribbon 入门》文章。

5. 基于配置中心 Apollo 实现动态路由

示例代码对应仓库:

「4. 基于注册中心实现动态路由」小节中,我们在配置文件中,添加了 Zuul “动态路由”。但是,如果每次进行路由的变更时,都需要修改配置文件,并重启 Zuul 实例,显然是不合适的。

因此,我们可以引入配置中心 Apollo 来实现动态路由的功能,将 zuul 配置项统一存储在 Apollo 中。同时,通过通过 Apollo 的实时监听器,在 zuul 发生变化时,刷新内存中的路由信息。

当然,Gateway 中我们还是会使用注册中心,目的是为了获取服务的实例列表,只是不再使用 Gateway 基于注册中心来的动态路由功能而已。

我们直接从「4. 基于注册中心实现动态路由」小节的 labx-21-sc-zuul-demo02-registry 项目,复制出本小节的 labx-21-sc-zuul-demo03-config-apollo 项目,搭建 Zuul 基于配置中心 Apollo 实现动态路由的示例。最终项目结构如下图:

 项目

分割线:先进行网关项目的改造。

5.1 引入依赖

修改 pom.xml 文件,引入配置中心 Apollo 相关的依赖如下:

<!--  引入 Apollo 客户端,内置对 Apollo 的自动化配置 -->
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.5.1</version>
</dependency>

5.2 配置文件

修改 application.yaml 配置文件,增加 Apollo 相关的配置项。完整配置如下:

server:
port: 8888

spring:
application:
name: zuul-application

cloud:
nacos:
# Nacos 作为注册中心的配置项
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址

# Apollo 相关配置项
app:
id: ${spring.application.name} # 使用的 Apollo 的项目(应用)编号
apollo:
meta: http://127.0.0.1:8080 # Apollo Meta Server 地址
bootstrap:
enabled: true # 是否开启 Apollo 配置预加载功能。默认为 false。
eagerLoad:
enable: true # 是否开启 Apollo 支持日志级别的加载时机。默认为 false。
namespaces: application # 使用的 Apollo 的命名空间,默认为 application。

zuul 配置项,我们都删除了,统一在 Apollo 中进行配置。

为了演示 Gateway 启动时,从 Apollo 加载 spring.cloud.gateway 配置项,作为初始的路由信息,我们在 Apollo 配置如下:

Apollo 配置项

配置对应文本内容如下:

zuul.servlet-path = /
zuul.routes.route_yudaoyuanma.path = /**
zuul.routes.route_yudaoyuanma.url = http://www.iocoder.cn

app.idapollo 配置项,为 Apollo 相关配置项。这里就不详细解释,毕竟 Apollo 不是主角。感兴趣的胖友,可以阅读《芋道 Spring Boot 配置中心 Apollo 入门》文章。

5.3 ZuulPropertiesRefresher

创建 ZuulPropertiesRefresher 类,监听 Apollo 中的zuul 发生变化时,刷新内存中的路由信息。代码如下:

@Component
public class ZuulPropertiesRefresher {

private static final Logger logger = LoggerFactory.getLogger(ZuulPropertiesRefresher.class);

@Autowired
private ApplicationContext applicationContext;

@Autowired
private RouteLocator routeLocator;

@ApolloConfigChangeListener(interestedKeyPrefixes = "zuul.") // <1>
public void onChange(ConfigChangeEvent changeEvent) {
refreshZuulProperties(changeEvent);
}

private void refreshZuulProperties(ConfigChangeEvent changeEvent) {
logger.info("Refreshing zuul properties!");

/*
* rebind configuration beans, e.g. ZuulProperties
* @see org.springframework.cloud.context.properties.ConfigurationPropertiesRebinder#onApplicationEvent
*/
// <2>
this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));

/*
* refresh routes
* @see org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration.ZuulRefreshListener#onApplicationEvent
*/
// <3>
this.applicationContext.publishEvent(new RoutesRefreshedEvent(routeLocator));

logger.info("Zuul properties refreshed!");
}

}

<1> 处,通过 Apollo 提供的 @ApolloConfigChangeListener 注解,声明监听 zuul. 配置项的刷新。

<2> 处,发布 EnvironmentChangeEvent 配置变更事件,从而被 Spring Cloud Context ConfigurationPropertiesRebinder 所监听,刷新 ZuulProperties 配置类。

<3> 处,发布 RoutesRefreshedEvent 路由刷新事件,从而被 Spring Cloud Zuul ZuulServerAutoConfiguration.ZuulRefreshListener 所监听,刷新内存中的 Zuul 路由信息

友情提示:这块涉及一定的知识量,胖友可以通过在对应的 Listener 监听器,打上相应的断点进行调试。

5.4 搭建用户服务

创建 labx-21-sc-user-service 项目,作为 user-service 用户服务。代码比较简单,艿艿就不瞎哔哔了。最终项目如下图所示:

5.5 简单测试

① 执行 UserServiceApplication 两次,启动两个 user-service 服务。

② 执行 ZuulApplication 启动网关。

使用浏览器,访问 http://127.0.0.1:8888/ 地址,返回艿艿的博客首页,如下图所示:

博客首页

③ 修改在 Apollo 的 zuul 配置项,转发请求到用户服务。如下图所示:

Apollo 配置项

配置对应文本内容如下:

zuul.servlet-path = /
zuul.routes.route_yudaoyuanma.path = /**
zuul.routes.route_yudaoyuanma.service-id = user-service

此时 IDEA 控制台看到 GatewayPropertiesRefresher 监听到 zuul 配置项刷新,并打印日志如下:

2020-05-04 00:26:31.763  INFO 52628 --- [Apollo-Config-2] c.i.s.l.z.ZuulPropertiesRefresher        : Refreshing zuul properties!
2020-05-04 00:26:31.864 INFO 52628 --- [Apollo-Config-2] c.i.s.l.z.ZuulPropertiesRefresher : Zuul properties refreshed!

④ 访问 http://127.0.0.1:8888/user/get?id=1 地址,返回 JSON 结果如下:

{
"id": 1,
"name": "没有昵称:1",
"gender": 2
}

请求经过网关后,转发到 user-service 服务成功。

6. 基于配置中心 Nacos 实现动态路由

示例代码对应仓库:

「4. 基于注册中心实现动态路由」小节中,我们在配置文件中,添加了 Zuul “动态路由”。但是,如果每次进行路由的变更时,都需要修改配置文件,并重启 Zuul 实例,显然是不合适的。

因此,我们可以引入配置中心 Config 来实现动态路由的功能,将 zuul 配置项统一存储在 Config 中。同时,通过通过 Config 的实时监听器,在 zuul 发生变化时,刷新内存中的路由信息。

当然,Zuul 中我们还是会使用注册中心,目的是为了获取服务的实例列表,只是不再使用 Zuul 基于注册中心来的动态路由功能而已。

我们直接从「4. 基于注册中心实现动态路由」小节的 labx-21-sc-zuul-demo02-registry 项目,复制出本小节的 labx-21-sc-zuul-demo03-config-nacos 项目,搭建 Zuul 基于配置中心 Nacos 实现动态路由的示例。最终项目结构如下图:

 项目

分割线:先进行网关项目的改造。

6.1 引入依赖

修改 pom.xml 文件,引入配置中心 Nacos 相关的依赖如下:

<!-- 引入 Spring Cloud Alibaba Nacos Config 相关依赖,将 Nacos 作为配置中心,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

6.2 配置文件

① 创建 bootstrap.yaml 配置文件,添加配置中心 Nacos 相关的配置。配置如下:

spring:
application:
name: zuul-application

cloud:
nacos:
# Nacos Config 配置项,对应 NacosConfigProperties 配置属性类
config:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址
namespace: # 使用的 Nacos 的命名空间,默认为 null
group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
name: # 使用的 Nacos 配置集的 dataId,默认为 spring.application.name
file-extension: yaml # 使用的 Nacos 配置集的 dataId 的文件拓展名,同时也是 Nacos 配置集的配置格式,默认为 properties

spring.cloud.nacos.config 配置项,为配置中心 Nacos 相关配置项。这里就不详细解释,毕竟 Nacos 不是主角。感兴趣的胖友,可以阅读《芋道 Spring Cloud Alibaba 配置中心 Nacos 入门》文章。

② 修改 application.yaml 配置文件,删除 Zuul 相关的配置。完整配置如下:

server:
port: 8888

spring:
cloud:
nacos:
# Nacos 作为注册中心的配置项
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址

zuul 配置项,我们都删除了,统一在配置中心 Nacos 中进行配置。

为了演示 Zuul 启动时,从 Nacos 加载 zuul 配置项,作为初始的路由信息,我们在 Nacos 配置如下:

Nacos 配置项

配置对应文本内容如下:

zuul:
servlet-path: /
routes:
route_yudaoyuanma:
path: /**
url: http://www.iocoder.cn

6.3 ZuulRouteRefreshListener

在 Nacos 配置发生变化时,Spring Cloud Alibaba Nacos Config 内置的监听器 会监听到配置刷新,发布 EnvironmentChangeEvent 配置变更事件。因此,我们实现自定义 ZuulRouteRefreshListener 监听器,来监听该事件。代码如下:

@Component
public class ZuulRouteRefreshListener implements ApplicationListener<EnvironmentChangeEvent> {

private static final Logger logger = LoggerFactory.getLogger(ZuulRouteRefreshListener.class);

@Autowired
private ApplicationEventPublisher publisher;

@Autowired
private RouteLocator routeLocator;

@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
// <1> 判断是否有 `zuul.` 配置变化
boolean zuulConfigUpdated = false;
for (String key : event.getKeys()) {
if (key.startsWith("zuul.")) {
zuulConfigUpdated = true;
break;
}
}
if (!zuulConfigUpdated) {
return;
}

// <2> 发布 RoutesRefreshedEvent 事件
this.publisher.publishEvent(new RoutesRefreshedEvent(routeLocator));
logger.info("发布 RoutesRefreshedEvent 事件完成,刷新 Zuul 路由");
}

}

<1> 处,判断 zuul. 配置项,是否发生变化。

<2> 处,发布 RoutesRefreshedEvent 路由刷新事件,从而被 Spring Cloud Zuul ZuulServerAutoConfiguration.ZuulRefreshListener 所监听,刷新内存中的 Zuul 路由信息

友情提示:这块涉及一定的知识量,胖友可以通过在对应的 Listener 监听器,打上相应的断点进行调试。

6.4 搭建用户服务

创建 labx-21-sc-user-service 项目,作为 user-service 用户服务。代码比较简单,艿艿就不瞎哔哔了。最终项目如下图所示:

6.5 简单测试

① 执行 UserServiceApplication 两次,启动两个 user-service 服务。

② 执行 ZuulApplication 启动网关。

使用浏览器,访问 http://127.0.0.1:8888/ 地址,返回艿艿的博客首页,如下图所示:

博客首页

③ 修改在 Nacos 的 zuul 配置项,转发请求到用户服务。如下图所示:

Nacos 配置项

配置对应文本内容如下:

zuul:
servlet-path: /
routes:
route_yudaoyuanma:
path: /**
service-id: user-service

此时 IDEA 控制台看到 ZuulRouteRefreshListener 监听到 zuul. 配置项刷新,并打印日志如下:

日志

④ 访问 http://127.0.0.1:8888/user/get?id=1 地址,返回 JSON 结果如下:

{
"id": 1,
"name": "没有昵称:1",
"gender": 2
}

请求经过网关后,转发到 user-service 服务成功。

7. 灰度发布

Spring Cloud Zuul 并未提供灰度发布功能。

友情提示:感兴趣的胖友,可以阅读《芋道 Spring Cloud 网关 Spring Cloud Gateway 入门》「8. 灰度发布」小节。

8. Zuul 过滤器

Zuul 的两大核心是路由过滤功能:

  • 路由功能:负责匹配请求到指定 Route 路由,从而转发请求到该路由对应的 url 后端 URL 或 service-id 服务实例上。
  • 过滤功能:负责对请求进行拦截,实现自定义的功能,例如说限流、熔断等等功能。

8.1 过滤器类型

Zuul 定义了 IZuulFilter 接口,定义了 Zuul 过滤器的两个基础方法。代码如下:

public interface IZuulFilter {

/**
* 是否进行过滤。如果是,则返回 true。
*/
boolean shouldFilter();

/**
* 执行过滤器的逻辑。
*/
Object run() throws ZuulException;

}

Zuul 定义了 ZuulFilter 抽象基类,定义了 Zuul 过滤器的类型执行顺序方法。代码如下:

public abstract class ZuulFilter implements IZuulFilter, Comparable<ZuulFilter> {

/**
* 执行类型。
*/
abstract public String filterType();

/**
* 执行顺序。
*/
abstract public int filterOrder();

}

过滤器一共分成四种类型,分别在不同阶段执行:

// FilterConstants.java

/**
* {@link ZuulFilter#filterType()} pre type.
* 前置类型:在 route 之前调用
* 使用场景:身份认证、记录请求日志、服务容错、服务限流...
*/
public static final String PRE_TYPE = "pre";

/**
* {@link ZuulFilter#filterType()} route type.
* 路由类型:路由请求到后端 URL 或服务实例上
* 使用场景:使用 Apache HttpClient 请求后端 URL、或使用 Netflix Ribbon 请求服务实例...
*/
public static final String ROUTE_TYPE = "route";

/**
* {@link ZuulFilter#filterType()} post type.
* 后置类型:
* 1. 发生异常时,在 error 之后调用
* 2. 正常执行时,最后调用
* 使用场景:收集监控信息、响应结果给客户端...
*/
public static final String POST_TYPE = "post";

/**
* {@link ZuulFilter#filterType()} error type.
* 错误类型:处理请求时发生的错误时被调用。
*/
public static final String ERROR_TYPE = "error";

这么说可能有点抽象,我们再来一起看一幅图和一段代码,即可清楚明白:

  • 一幅图
  • 一段代码

8.2 核心过滤器

Zuul 自带了很多 ZuulFilter 实现类,如下图所示:

ZuulFilter 实现类

友情提示:如下的过滤器,胖友先简单看看。后续可以进行调试,进一步深入了解。

① pre 过滤器

名称 优先级 作用
ServletDetectionFilter -3 检测当前请求是通过 DispatcherServlet 处理运行的还是 ZuulServlet 运行处理的。
Servlet30WrapperFilter -2 对原始的HttpServletRequest 进行包装。
FormBodyWrapperFilter -1 将 Content-Type为 application/x-www-form-urlencodedmultipart/form-data 的请求包装成 FormBodyRequestWrapper对 象。

② route 过滤器

名称 优先级 作用
DebugFilter 1 根据 zuul.debug.request 的配置来决定是否打印 debug 日志。
PreDecorationFilter 5 对当前请求进行预处理以便执行后续操作。
RibbonRoutingFilter 10 通过 Ribbon 和 Hystrix 来向服务实例发起请求,并将请求结果进行返回。
SimpleHostRoutingFilter 100 只对请求上下文中有 routeHost 参数的进行处理,直接使用 HttpClient 向 routeHost 对应的物理地址进行转发。
SendForwardFilter 500 只对请求上下文中有 forward.to 参数的进行处理,进行本地跳转。

③ post 过滤器

名称 优先级 作用
SendErrorFilter 0 当其他过滤器内部发生异常时的会由它来进行处理,产生错误响应。
SendResponseFilter 1000 利用请求上下文的响应信息来组织请求成功的响应内容。

8.3 自定义过滤器

示例代码对应仓库:labx-21-sc-zuul-demo05-custom-zuul-filter

一般情况下,我们在 Zuul 上会去做的拓展,主要集中在 Filter 上,例如说接入认证服务。因此,我们来搭建 Zuul 自定义 Filter 实现的示例,提供“伪劣”的认证功能。还是老样子,从「3. 快速入门」小节的 labx-21-sc-zuul-demo01 项目,复制出本小节的 labx-21-sc-zuul-demo05-custom-zuul-filter 项目,最终项目结构如下图:

 项目

8.3.1 AuthZuulFilter

创建 AuthZuulFilter 类,认证过滤器,提供“伪劣”的认证功能。代码如下:

@Component
public class AuthZuulFilter extends ZuulFilter {

/**
* 外部请求 Header - token 认证令牌 <2.1>
*/
private static final String DEFAULT_TOKEN_HEADER_NAME = "token";
/**
* 转发请求 Header - userId 用户编号 <2.2>
*/
private static final String DEFAULT_HEADER_NAME = "user-id";

/**
* token 和 userId 的映射 <2.3>
*/
private static Map<String, Integer> TOKENS = new HashMap<String, Integer>();

static {
TOKENS.put("yunai", 1);
}

public String filterType() {
return FilterConstants.PRE_TYPE; // <3.1> 前置过滤器
}

public int filterOrder() {
return 0;
}

public boolean shouldFilter() {
return true; // <3.2> 需要过滤
}

public Object run() throws ZuulException {
// 获取当前请求上下文
RequestContext ctx = RequestContext.getCurrentContext();
// <4.1> 获得 token
HttpServletRequest request = ctx.getRequest();
String token = request.getHeader(DEFAULT_TOKEN_HEADER_NAME);

// <4.2> 如果没有 token,则不进行认证。因为可能是无需认证的 API 接口
if (!StringUtils.hasText(token)) {
return null;
}

// <4.3> 进行认证
Integer userId = TOKENS.get(token);

// <4.4> 通过 token 获取不到 userId,说明认证不通过
if (userId == null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401); // 响应 401 状态码
return null;
}

// <4.5> 认证通过,将 userId 添加到 Header 中
ctx.getZuulRequestHeaders().put(DEFAULT_HEADER_NAME, String.valueOf(userId));
return null;
}

}

① 集成 ZuulFilter 抽象类,并在类上添加 @Component 注解,保证 Zuul 能够加载到 AuthZuulFilter 过滤器。

<2.1><2.2> 处,定义了认证 Token 的 Header 名字 token,和认证后的 UserId 的 Header 名字 user-id

<2.3> 处,定义了一个存储 tokenuserId 映射的 Map,毕竟咱仅仅是一个提供“伪劣”的认证功能的 Filter。

<3.1> 处,设置过滤器的类型为 pre 前置过滤器。

<3.2> 处,设置过滤器需要执行。

<4.1> 处,从请求 Header 中获取 token,作为认证标识。

<4.2> 处,如果没有 token,则不进行认证。因为可能是无需认证的 API 接口。

<4.3> 处,“伪劣”的认证逻辑,哈哈哈~实际场景下,一般调用远程的认证服务。

<4.4> 处,通过 token 获取不到 userId,说明认证不通过,设置返回 401 状态码。

<4.5> 处,通过 token 获取到 userId,说明认证通过,将 userId 添加到请求 Header,从而实现将 userId 传递给目标 URI。

友情提示:在 Spring Cloud Security 项目中,提供了 Zuul 的支持,胖友可以后续去愁一愁噢。

8.3.2 简单测试

① 执行 ZuulApplication 启动网关。

② 使用 Postman 模拟请求 Header tokenyunai1,演示认证不通过的情况,结果如下图:

认证不通过

③ 使用 Postman 模拟请求 Header tokenyunai,演示认证通过的情况,结果如下图:

认证通过

8.4 禁用过滤器

在 Spring Cloud Zuul 中,我们可以通过在配置文件中,添加 zuul.<过滤器名>.<过滤器类型>.disable=true 配置项来禁用指定过滤器。

例如说,我们想要禁用 SendResponseFilter 后置过滤器,则可以添加 zuul.SendResponseFilter.post.disable=true 配置项来禁用。

9. 请求限流

Spring Cloud Zuul 并未提供请求限流功能。

友情提示:感兴趣的胖友,可以阅读《芋道 Spring Cloud 网关 Spring Cloud Gateway 入门》「10. 请求限流」小节。

10. 基于 Hystrix 实现服务容错

示例代码对应仓库:

Zuul 作为服务网关,为了避免被调用的服务拖垮,在使用 Ribbon 调用后端服务时,集成 Hystrix 进行不同 Route 的隔离,进入实现服务的容错。具体的,后续胖友可以看看 AbstractRibbonCommand 的源码,如下图所示:

AbstractRibbonCommand

Hystrix 库,是 Netflix 开源的一个针对分布式系统的延迟和容错库。

Hystrix 供分布式系统使用,提供延迟和容错功能,隔离远程系统、访问和第三方程序库的访问点,防止级联失败,保证复杂的分布系统在面临不可避免的失败时,仍能有其弹性。

下面,我们来搭建 Zuul 基于 Hystrix 实现服务容错的使用示例。还是老样子,从「4. 基于注册中心实现动态路由」小节的 labx-21-sc-zuul-demo02-registry 项目,复制出本小节的 labx-21-sc-zuul-demo07-hystrix 项目,最终项目结构如下图:

 项目

分割线:先进行网关项目的改造。

10.1 引入依赖

因为 spring-cloud-starter-netflix-zuul 默认引入了 Hystrix 相关依赖,所以我们无需主动引入。如下图所示:

Hystrix 相关依赖

10.2 FallbackProvider

Spring Cloud Zuul 定义了 FallbackProvider 接口,提供服务调用失败的 Fallback 降级的响应,例如说 Hystrix Fallback。代码如下:

public interface FallbackProvider {

/**
* The route this fallback will be used for.
* @return The route the fallback will be used for.
*/
String getRoute();

/**
* Provides a fallback response based on the cause of the failed execution.
* @param route The route the fallback is for
* @param cause cause of the main method failure, may be <code>null</code>
* @return the fallback response
*/
ClientHttpResponse fallbackResponse(String route, Throwable cause);

}

  • #getRoute() 方法,该 FallbackProvider 匹配的 Route 编号,例如说 route_users。如果想要匹配所有 Route 则,返回 *
  • #fallbackResponse() 方法,处理指定 route 路由发生的 cause 异常,提供 Fallback 时的 ClientHttpResponse 响应

这里,我们来实现一个 ApiFallbackProvider,响应结果为 {"code": 500, "message": "Service unavailable:${具体原因}"}。代码如下:

@Component
public class ApiFallbackProvider implements FallbackProvider {

public String getRoute() {
return "*";
}

public ClientHttpResponse fallbackResponse(String route, final Throwable cause) {
return new ClientHttpResponse() {

public HttpStatus getStatusCode() {
return HttpStatus.OK;
}

public int getRawStatusCode() {
return HttpStatus.OK.value();
}

public String getStatusText() {
return HttpStatus.OK.getReasonPhrase();
}

public void close() {}

public InputStream getBody() { // 响应内容
String bodyText = String.format("{\"code\": 500,\"message\": \"Service unavailable:%s\"}", cause.getMessage());
return new ByteArrayInputStream(bodyText.getBytes());
}

public HttpHeaders getHeaders() { // 响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON); // json 返回
return headers;
}

};
}

}

  • 代码比较简单,胖友自己瞅两眼就懂了。

10.3 搭建用户服务

创建 labx-21-sc-user-service 项目,作为 user-service 用户服务。代码比较简单,艿艿就不瞎哔哔了。最终项目如下图所示:

10.4 简单测试

① 执行 UserServiceApplication 启动 user-service 服务,执行 ZuulApplication 启动网关。

② 使用浏览器访问 http://127.0.0.1:8888/users/user/get?id=1 接口,成功调用 user-service 服务,并返回如下:

{
"id": 1,
"name": "没有昵称:1",
"gender": 2
}

③ 停止 UserServiceApplication 关闭 user-service 服务,模拟服务不可用的情况。使用浏览器访问 http://127.0.0.1:8888/users/user/get?id=1 接口,失败调用 user-service 服务,并返回如下:

{
"code": 500,
"message": "Service unavailable:null"
}

此时,我们快速使用浏览器访问 http://127.0.0.1:8888/users/user/get?id=1 接口,多次失败调用 user-service 服务,会触发 Hystrix 熔断,并返回如下:

{
"code": 500,
"message": "Service unavailable:Hystrix circuit short-circuited and is OPEN"
}

11. 基于 Sentinel 实现服务容错

示例代码对应仓库:labx-21-sc-zuul-demo07-sentinel

本小节我们来进行 Zuul 和 Sentinel 的整合,使用 Sentinel 进行 Zuul 的流量保护。

Sentinel 是阿里中间件团队开源的,面向分布式服务架构的轻量级流量控制产品,主要以流量为切入点,从流量控制熔断降级系统负载保护等多个维度来帮助用户保护服务的稳定性。

Sentinel 提供了 sentinel-zuul-adapter 子项目,已经对 Zuul 进行适配,所以我们只要引入它,基本就完成了 Zuul 和 Sentinel 的整合,贼方便。

友情提示:本小节会引用《Sentinel 官方文档 —— 网关限流》的内容。

 图

下面,我们来搭建 Gateway 基于 Sentinel 实现服务容错的使用示例。还是老样子,从「3. 快速入门」小节的 labx-21-sc-zuul-demo01 项目,复制出本小节的 labx-21-sc-zuul-demo07-sentinel 项目,最终项目结构如下图:

 项目

11.1 引入依赖

修改 pom.xml 文件,额外引入 Sentinel 相关的依赖如下:

<!-- 引入 Spring Cloud Alibaba Sentinel 相关依赖,使用 Sentinel 提供服务保障,并实现对其的自动配置 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>

11.2 配置文件

修改 application.yaml 配置文件,增加 Sentinel 的配置项。完整配置如下:

server:
port: 8888

spring:
application:
name: zuul-application

cloud:
nacos:
# Nacos 作为注册中心的配置项
discovery:
server-addr: 127.0.0.1:8848 # Nacos 服务器地址

sentinel:
eager: true # 是否饥饿加载。默认为 false 关闭
transport:
dashboard: localhost:7070 # 是否饥饿加载。
# Sentinel 对 Zuul 的专属配置项,对应 SentinelZuulProperties 类
zuul:
order:
pre: 10000 # 前置过滤器 SentinelZuulPreFilter 的顺序
post: 1000 # 后置过滤器 SentinelZuulPostFilter 的顺序
error: -1 # 错误过滤器 SentinelZuulErrorFilter 的顺序

# Zuul 配置项,对应 ZuulProperties 配置类
zuul:
servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul
# 路由配置项,对应 ZuulRoute Map
routes:
yudaoyuanma: # 这是一个 Route 编号
path: /**
url: http://www.iocoder.cn

① 为了测试方便,我们修改 zuul.routes 配置项,所有请求都转发到艿艿的博客 http://www.iocoder.cn

spring.cloud.sentinel 配置项,是 Spring Cloud Sentinel 的配置项,后续胖友可以看看《芋道 Spring Cloud Alibaba 服务容错 Sentinel 入门》文章。

友情提示:艿艿本机搭建的 Sentinel 控制台启动在 7070 端口。

spring.cloud.sentinel.zuul 配置项,是 Sentinel 对 Zuul 的专属配置项,对应 SentinelZuulProperties 类。

  • order:配置 Sentinel 拓展出的 Zuul 过滤器 SentinelZuulPreFilter、SentinelZuulPostFilter、SentinelZuulErrorFilter 的顺序。

11.3 ZuulBlockFallbackProvider

Sentinel 定义了 ZuulBlockFallbackProvider 接口,提供转发请求被 block 的 Fallback 降级的响应。代码如下:

public interface ZuulBlockFallbackProvider {

/**
* The route this fallback will be used for.
* @return The route the fallback will be used for.
*/
String getRoute();

/**
* Provides a fallback response based on the cause of the failed execution.
*
* @param route The route the fallback is for
* @param cause cause of the main method failure, may be <code>null</code>
* @return the fallback response
*/
BlockResponse fallbackResponse(String route, Throwable cause);
}

  • #getRoute() 方法,该 ZuulBlockFallbackProvider 匹配的 Route 编号,例如说 route_users。如果想要匹配所有 Route 则,返回 *
  • #fallbackResponse() 方法,处理指定 route 路由发生的 cause 异常,提供 Fallback 时的 BlockResponse 响应

Sentinel 提供了 ZuulBlockFallbackProvider 默认实现类 DefaultBlockFallbackProvider,提供默认响应,代码如下:

public class DefaultBlockFallbackProvider implements ZuulBlockFallbackProvider {

@Override
public String getRoute() {
return "*"; // 匹配所有 Route
}

@Override
public BlockResponse fallbackResponse(String route, Throwable cause) {
if (cause instanceof BlockException) {
return new BlockResponse(429, "Sentinel block exception", route);
} else {
return new BlockResponse(500, "System Error", route);
}
}
}

这里,我们自定义 ZuulBlockFallbackProvider 实现类 CustomBlockFallbackProvider,提供自定义响应,代码如下:

@Component
public class CustomBlockFallbackProvider implements ZuulBlockFallbackProvider {

@PostConstruct
public void init() {
ZuulBlockFallbackManager.registerProvider(this); // <X> 注册到 ZuulBlockFallbackManager
}

public String getRoute() {
return "*";
}

public BlockResponse fallbackResponse(String route, Throwable cause) {
if (cause instanceof BlockException) {
return new BlockResponse(429, "你被 Block 啦!", route);
} else {
return new BlockResponse(500, "系统异常", route);
}
}

}

11.4 ZuulApplication

修改 ZuulApplication 类的代码,声明这是一个 Zuul 应用。代码如下:

@SpringBootApplication
@EnableZuulProxy // 开启 Zuul 网关
public class ZuulApplication {

public static void main(String[] args) {
System.setProperty(SentinelConfig.APP_TYPE, ConfigConstants.APP_TYPE_ZUUL_GATEWAY); // 【重点】设置应用类型为 Zuul
SpringApplication.run(ZuulApplication.class, args);
}

}

11.5 简单测试

① 执行 ZuulApplication 启动网关。

访问 Sentinel 控制台,可以看到网关已经成功注册上。如下图所示:

Sentinel 控制台

② 点击「流控规则」菜单,我们来给路由 yudaoyuanma 创建一个网关流控规则,如下图所示:

创建流控规则

  • 创建了针对路由 yudaoyuanma统一流控规则,允许每个 URL 的 QPS 上限为 3。

使用浏览器,快速访问 http://www.iocoder.cn 地址 4 次,会发现被 Sentinel 限流,返回 {"code":429, "message":"你被 Block 啦!", "route":"yudaoyuanma"} 结果。该文字提示,就是我们自定义的 CustomBlockFallbackProvider 提供的。

③ 下面,我们来给 /categories/** 路径,配置单独流控规则。

点击「API 管理」菜单,我们先创建一个包含 /categories/**API 分组,如下图所示:

创建 API 分组

点击「流控规则」菜单,我们再给 API 分组创建一个网关流控规则,如下图所示:创建流控规则

  • 创建了针对该 API 分组的单独流控规则,允许每个 URL 的 QPS 上限为 1。

友情提示:目前该功能,在 Zuul 的 servlet-path = / 时存在 BUG,具体可见 ISSUE#1109 的讨论。

因此下面的演示,暂时只是艿艿期待的 YY 结果哈~

使用浏览器,快速访问 http://127.0.0.1:8888/categories/Spring-Cloud/ 地址 2 次,会发现被 Sentinel 限流,返回 {"code":429, "message":"你被 Block 啦!", "route":"yudaoyuanma"} 结果。

注意,虽然我们给 /categories/** 配置了单独的流控规则,但是通过路由配置的统一的流控规则也是生效的,也会作用到 /categories/** 上,即叠加的效果。

11.6 网关限流规则

sentinel-zuul-adapter 项目增加了网关限流规则GatewayFlowRule),针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。

GatewayFlowRule 的字段解释如下:

  • resource:资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
  • resourceMode:规则是针对 API Gateway 的 route 还是用户在 Sentinel 中定义的 API 分组,默认是 route。
  • grade:限流指标维度,同限流规则grade 字段。
  • count:限流阈值
  • intervalSec:统计时间窗口,单位是秒,默认是 1 秒。
  • controlBehavior:流量整形的控制效果,同限流规则controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。
  • burst:应对突发请求时额外允许的请求数目。
  • maxQueueingTimeoutMs:匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
  • paramItem:参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
    • parseStrategy:从请求中提取参数的策略,目前支持提取来源 IP、Host、任意 Header 和任意 URL 参数四种策略。
    • fieldName:若提取策略选择 Header 模式或 URL 参数模式,则需要指定对应的 header 名称或 URL 参数名称。
    • pattern:参数值的匹配模式,只有匹配该模式的请求属性值会纳入统计和流控;若为空则统计该请求属性的所有值。
    • matchStrategy:参数值的匹配策略,目前支持精确匹配、子串匹配和正则匹配三种策略。

具体的示例,可以看看 sentinel-gw-flow.json 配置文件,内容如下:

[
{
"resource": "yudaoyuanma",
"count": 3
},
{
"resource": "yudaoyuanma_customized_api",
"count": 1
}
]

11.7 API 定义分组

sentinel-zuul-adapter 项目增加了API 定义分组ApiDefinition),用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 API 叫 my_api,请求 path 模式为 /foo/**/baz/** 的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API 分组维度进行限流。

ApiDefinition 的字段解释如下:

具体的示例,可以看看 sentinel-gw-api-group.json 配置文件,内容如下:

[
{
"apiName": "yudaoyuanma_customized_api",
"predicateItems": [
{
"pattern": "/categories/**",
"matchStrategy": 1
},
{
"items": [
{
"pattern": "/Dubbo/good-collection/",
"matchStrategy": 0
},
{
"pattern": "/SkyWalking/**",
"matchStrategy": 1
}
]
}
]
}
]

12. 监控端点

示例代码对应仓库:labx-21-sc-zuul-demo09-actuator

Spring Cloud Zuul 的 RoutesEndpointFiltersEndpoint 类,基于 Spring Boot Actuator,提供了自定义监控端点,实现了 Zuul 的监控管理的功能。整理如下表格:

路径 用途
GET /routes 获得所有路由(简要)
GET /routes/details 获得指定路由(明细)
POST /routes 发布 RoutesRefreshedEvent 事件
GET /filters 获得所有过滤器

下面,我们来搭建 Zuul 的监控端点的使用示例。还是老样子,从「3. 快速入门」小节的 labx-08-sc-gateway-demo01 项目,复制出本小节的 labx-21-sc-zuul-demo09-actuator 项目,最终项目结构如下图:

 项目

12.1 引入依赖

因为 spring-cloud-starter-netflix-zuul 默认引入了 Spring Boot Actuator 相关依赖,所以我们无需主动引入。如下图所示:

Spring Boot Actuator 相关依赖

12.2 配置文件

修改 application.yaml 配置文件,额外增加 Spring Boot Actuator 配置项。完成配置如下:

server:
port: 8888

spring:
application:
name: zuul-application

# Zuul 配置项,对应 ZuulProperties 配置类
zuul:
servlet-path: / # ZuulServlet 匹配的路径,默认为 /zuul
# 路由配置项,对应 ZuulRoute Map
routes:
route_yudaoyuanma:
path: /blog/**
url: http://www.iocoder.cn
route_oschina:
path: /oschina/**
url: https://www.oschina.net

management:
endpoints:
web:
exposure:
include: '*' # 需要开放的端点。默认值只打开 health 和 info 两个端点。通过设置 * ,可以开放所有端点。
endpoint:
# Health 端点配置项,对应 HealthProperties 配置类
health:
enabled: true # 是否开启。默认为 true 开启。
show-details: ALWAYS # 何时显示完整的健康信息。默认为 NEVER 都不展示。可选 WHEN_AUTHORIZED 当经过授权的用户;可选 ALWAYS 总是展示。
server:
port: 18888 # 单独设置端口,因为 8888 端口全部给 Zuul 了

① 增加 management 配置项,设置的 Actuator 配置。每个配置项的作用,胖友看下艿艿添加的注释。如果还不理解的话,后续看下《芋道 Spring Boot 监控端点 Actuator 入门》文章。

下面,执行 ZuulApplication 启动网关,测试每一个端点。

12.3 路由端点

RoutesEndpoint 提供了 Zuul 路由相关的端点。

GET 请求 http://127.0.0.1:18888/actuator/routes/ 地址,获得所有路由(简要)。结果如下:

{
"/blog/**": "http://www.iocoder.cn",
"/oschina/**": "https://www.oschina.net"
}

② 请求 http://127.0.0.1:18888/actuator/routes/details 地址,获得所有路由(明细)。结果如下:

{
"/blog/**": {
"id": "route_yudaoyuanma",
"fullPath": "/blog/**",
"location": "http://www.iocoder.cn",
"path": "/**",
"prefix": "/blog",
"retryable": false,
"customSensitiveHeaders": false,
"prefixStripped": true
},
"/oschina/**": {
"id": "route_oschina",
"fullPath": "/oschina/**",
"location": "https://www.oschina.net",
"path": "/**",
"prefix": "/oschina",
"retryable": false,
"customSensitiveHeaders": false,
"prefixStripped": true
}
}

POST 请求 http://127.0.0.1:18888/actuator/routes/ 地址,发布 RoutesRefreshedEvent 并获得所有路由(简要)。结果如下:

{
"/blog/**": "http://www.iocoder.cn",
"/oschina/**": "https://www.oschina.net"
}

12.4 过滤器端点

FiltersEndpoint 提供了 Zuul 过滤器相关的端点。

GET 请求 http://127.0.0.1:18888/actuator/filters 地址,获取所有过滤器。结果如下图:

过滤器

666. 彩蛋

至此,我们已经完成 Spring Cloud Zuul 的学习。如下是 Zuul 相关的官方文档:

更多关于 Zuul 的内容,胖友可以访问《Zuul 实现原理与源码解析系统 —— 精品合集》

文章目录
  1. 1. 1. 概述
  2. 2. 2. 为什么使用网关?
  3. 3. 3. 快速入门
    1. 3.1. 3.1 引入依赖
    2. 3.2. 3.2 配置文件
    3. 3.3. 3.3 ZuulApplication
    4. 3.4. 3.4 简单测试
  4. 4. 4. 基于注册中心实现动态路由
    1. 4.1. 4.1 引入依赖
    2. 4.2. 4.2 配置文件
    3. 4.3. 4.3 搭建用户服务
    4. 4.4. 4.4 简单测试
  5. 5. 5. 基于配置中心 Apollo 实现动态路由
    1. 5.1. 5.1 引入依赖
    2. 5.2. 5.2 配置文件
    3. 5.3. 5.3 ZuulPropertiesRefresher
    4. 5.4. 5.4 搭建用户服务
    5. 5.5. 5.5 简单测试
  6. 6. 6. 基于配置中心 Nacos 实现动态路由
    1. 6.1. 6.1 引入依赖
    2. 6.2. 6.2 配置文件
    3. 6.3. 6.3 ZuulRouteRefreshListener
    4. 6.4. 6.4 搭建用户服务
    5. 6.5. 6.5 简单测试
  7. 7. 7. 灰度发布
  8. 8. 8. Zuul 过滤器
    1. 8.1. 8.1 过滤器类型
    2. 8.2. 8.2 核心过滤器
    3. 8.3. 8.3 自定义过滤器
      1. 8.3.1. 8.3.1 AuthZuulFilter
      2. 8.3.2. 8.3.2 简单测试
    4. 8.4. 8.4 禁用过滤器
  9. 9. 9. 请求限流
  10. 10. 10. 基于 Hystrix 实现服务容错
    1. 10.1. 10.1 引入依赖
    2. 10.2. 10.2 FallbackProvider
    3. 10.3. 10.3 搭建用户服务
    4. 10.4. 10.4 简单测试
  11. 11. 11. 基于 Sentinel 实现服务容错
    1. 11.1. 11.1 引入依赖
    2. 11.2. 11.2 配置文件
    3. 11.3. 11.3 ZuulBlockFallbackProvider
    4. 11.4. 11.4 ZuulApplication
    5. 11.5. 11.5 简单测试
    6. 11.6. 11.6 网关限流规则
    7. 11.7. 11.7 API 定义分组
  12. 12. 12. 监控端点
    1. 12.1. 12.1 引入依赖
    2. 12.2. 12.2 配置文件
    3. 12.3. 12.3 路由端点
    4. 12.4. 12.4 过滤器端点
  13. 13. 666. 彩蛋