Spring Cloud Zuul 网关服务

Posted by 暮夏有五 on 2021-02-06
Estimated Reading Time 8 Minutes
Words 2.2k In Total
Viewed Times

Zuul 简介


Spring Cloud Zuul 是Spring Cloud Netflix 子项目的核心组件之一,可以作为微服务架构中的API网关使用,支持动态路由与过滤功能,本文将对其用法进行详细介绍。

API 网关为微服务架构中的服务提供了统一的访问入口,客户端通过 API 网关访问相关服务。API 网关的定义类似于设计模式中的门面模式,它相当于整个微服务架构中的门面,所有客户端的访问都通过它来进行路由及过滤。它实现了请求路由、负载均衡、校验过滤、服务容错、服务聚合等功能。

创建项目模块


这里我们创建一个 zuul-proxy 模块来演示 zuul 的常用功能。

引入依赖

在 pom.xml 中添加相关依赖

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>

相关配置

在 application.yml 中进行配置

1
2
3
4
5
6
7
8
9
10
11
server:
port: 8801
spring:
application:
name: zuul-proxy
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8001/eureka/

在启动类上添加 @EnableZuulProxy 注解来启用 Zuul 的 API 网关功能

1
2
3
4
5
6
7
8
9
10
@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulProxyApplication {

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

}

常用功能


启动相关服务

这里我们通过启动 eureka-server,两个 user-service,feign-service 和 zuul-proxy 来演示 Zuul 的常用功能。

img

配置路由规则

我们可以通过修改application.yml中的配置来配置路由规则,这里我们将匹配/userService/**的请求路由到user-service服务上去,匹配/feignService/**的请求路由到feign-service上去。

1
2
3
4
5
6
zuul:
routes: #给服务配置路由
user-service:
path: /userService/**
feign-service:
path: /feignService/**

默认路由规则

Zuul 和 Eureka 结合使用,可以实现路由的自动配置,自动配置的路由以服务名称为匹配路径,相当于如下配置:

1
2
3
4
5
6
zuul:
routes: #给服务配置路由
user-service:
path: /user-service/**
feign-service:
path: /feign-service/**

如果不想使用默认的路由规则,可以添加以下配置来忽略默认路由配置:

1
2
zuul:
ignored-services: user-service,feign-service #关闭默认路由配置

负载均衡功能

多次调用 http://localhost:8801/user-service/user/1 进行测试,可以发现运行在 8201 和 8202 的 user-service 服务交替打印信息。

配置访问前缀

我们可以通过以下配置来给网关路径添加前缀,此处添加了 /proxy 前缀,这样我们需要访问 http://localhost:8801/proxy/user-service/user/1 才能访问到 user-service 中的接口。

1
2
zuul:
prefix: /proxy #给网关路由添加前缀

Header过滤及重定向添加Host

Zuul 在请求路由时,默认会过滤掉一些敏感的头信息,以下配置可以防止路由时的 Cookie 及 Authorization 的丢失:

1
2
zuul:
sensitive-headers: Cookie,Set-Cookie,Authorization #配置过滤敏感的请求头信息,设置为空就不会过滤

Zuul 在请求路由时,不会设置最初的 host 头信息,以下配置可以解决:

1
2
zuul:
add-host-header: true #设置为true重定向是会添加host请求头

查看路由信息

我们可以通过 Spring Boot Actuator 来查看 Zuul 中的路由信息。

在 pom.xml 中添加相关依赖:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

修改 application.yaml 配置文件,开启查看路由的端点:

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: 'routes'

通过访问 http://localhost:8801/actuator/routes 查看简单路由信息:

img

通过访问 http://localhost:8801/actuator/routes/details 查看详细路由信息:

img

过滤器


路由与过滤是 Zuul 的两大核心功能,路由功能负责将外部请求转发到具体的服务实例上去,是实现统一访问入口的基础,过滤功能负责对请求过程进行额外的处理,是请求校验过滤及服务聚合的基础。

过滤器类型

Zuul 中有以下几种典型的过滤器类型。

  • pre:在请求被路由到目标服务前执行,比如权限校验、打印日志等功能;
  • routing:在请求被路由到目标服务时执行,这是使用Apache HttpClient或Netflix Ribbon构建和发送原始HTTP请求的地方;
  • post:在请求被路由到目标服务后执行,比如给目标服务的响应添加头信息,收集统计数据等功能;
  • error:请求在其他阶段发生错误时执行。

过滤器的生命周期

下图描述了一个 HTTP 请求到达 API 网关后,如何在各种不同类型的过滤器中流转的过程:

img

自定义过滤器

接下来我们自定义一个过滤器来演示下过滤器的作用。

添加 PreLogFilter 类继承 ZuulFilter

这是一个前置过滤器,用于在请求路由到目标服务前打印请求日志。

1
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
@Component
public class PreLogFilter extends ZuulFilter {
private Logger LOGGER = LoggerFactory.getLogger(this.getClass());

/**
* 过滤器类型,有pre、routing、post、error四种。
*/
@Override
public String filterType() {
return "pre";
}

/**
* 过滤器执行顺序,数值越小优先级越高。
*/
@Override
public int filterOrder() {
return 1;
}

/**
* 是否进行过滤,返回true会执行过滤。
*/
@Override
public boolean shouldFilter() {
return true;
}

/**
* 自定义的过滤器逻辑,当shouldFilter()返回true时会执行。
*/
@Override
public Object run() throws ZuulException {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
String host = request.getRemoteHost();
String method = request.getMethod();
String uri = request.getRequestURI();
LOGGER.info("Remote host:{},method:{},uri:{}", host, method, uri);
return null;
}
}

过滤器功能演示

添加过滤器后,我们访问 http://localhost:8801/user-service/user/1 测试下,会打印如下日志。

1
2019-10-05 15:13:10.232  INFO 11040 --- [nio-8801-exec-7] com.antonio.cloud.filter.PreLogFilter      : Remote host:0:0:0:0:0:0:0:1,method:GET,uri:/user-service/user/1

核心过滤器

过滤器名称 过滤类型 优先级 过滤器的作用
ServletDetectionFilter pre -3 检测当前请求是通过DispatcherServlet处理运行的还是ZuulServlet运行处理的。
Servlet30WrapperFilter pre -2 对原始的HttpServletRequest进行包装。
FormBodyWrapperFilter pre -1 将Content-Type为application/x-www-form-urlencoded或multipart/form-data的请求包装成FormBodyRequestWrapper对象。
DebugFilter route 1 根据zuul.debug.request的配置来决定是否打印debug日志。
PreDecorationFilter route 5 对当前请求进行预处理以便执行后续操作。
RibbonRoutingFilter route 10 通过Ribbon和Hystrix来向服务实例发起请求,并将请求结果进行返回。
SimpleHostRoutingFilter route 100 只对请求上下文中有routeHost参数的进行处理,直接使用HttpClient向routeHost对应的物理地址进行转发。
SendForwardFilter route 500 只对请求上下文中有forward.to参数的进行处理,进行本地跳转。
SendErrorFilter post 0 当其他过滤器内部发生异常时的会由它来进行处理,产生错误响应。
SendResponseFilter post 1000 利用请求上下文的响应信息来组织请求成功的响应内容。

禁用过滤器

我们可以对过滤器进行禁用的配置,配置格式如下:

1
2
3
4
zuul:
filterClassName:
filter:
disable: true

以下是禁用 PreLogFilter 的示例配置:

1
2
3
4
zuul:
PreLogFilter:
pre:
disable: true

Ribbon 和 Hystrix 的支持


由于 Zuul 自动集成了 Ribbon 和 Hystrix,所以 Zuul 天生就有负载均衡和服务容错能力,我们可以通过 Ribbon 和 Hystrix 的配置来配置 Zuul 中的相应功能。

可以使用 Hystrix 的配置来设置路由转发时 HystrixCommand 的执行超时时间:

1
2
3
4
5
6
7
hystrix:
command: #用于控制HystrixCommand的行为
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 1000 #配置HystrixCommand执行的超时时间,执行超过该时间会进行服务降级处理

可以使用 Ribbon 的配置来设置路由转发时请求连接及处理的超时时间:

1
2
3
ribbon: #全局配置
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)

常用配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
zuul:
routes: #给服务配置路由
user-service:
path: /userService/**
feign-service:
path: /feignService/**
ignored-services: user-service,feign-service #关闭默认路由配置
prefix: /proxy #给网关路由添加前缀
sensitive-headers: Cookie,Set-Cookie,Authorization #配置过滤敏感的请求头信息,设置为空就不会过滤
add-host-header: true #设置为true重定向是会添加host请求头
retryable: true # 关闭重试机制
PreLogFilter:
pre:
disable: false #控制是否启用过滤器

更多请移步:https://antoniopeng.com


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !