Overview
Spring Cloud Zuul is one of the core components of the Spring Cloud Netflix sub-project. It can be used as an API gateway in a microservice architecture and has the following uses:
- Authentication: Authenticate requests to access each service and reject requests that fail authentication.
- Monitoring: Monitor system requests, record request response logs, and count current system visits and monitoring status in real time.
- Stress testing: Helps conduct controlled stress testing of the cluster
- Grayscale testing: Grayscale release can ensure the stability of the overall system. Problems can be discovered and adjusted during the initial grayscale.
- Dynamic routing: Distribute requests to specified clients based on the request path
- Load control: unified control of client request pressure, and requests that exceed the pressure are directly rejected.
- Static response processing: build partial responses directly at the edge to avoid them flowing into the internal cluster
Build Zuul gateway
Create the zuul-service project and introduce dependencies. This project is based on SpringBoot 2.3.1, SpringCloud Hoxton.SR12
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
Add the following configuration in the application.yml configuration file:
server:
port: 9080 # 指定运行端口
spring:
application:
name: zuul-service # 指定服务名称
zuul:
routes:
blog:
path: /baidu/**
url: https://www.baidu.com # url用于配置符合path的请求路径路由到的服务地址
@EnableZuulProxy
Add annotations to the startup class
@EnableZuulProxy
@SpringBootApplication
public class ZuulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServiceApplication.class, args);
}
}
Spring Cloud Netflix Zuul provides a number of filters, depending on the Zuul annotations enabled, and @EnableZuulProxy
is @EnableZuulServer
a superset of @EnableZuulServer
all filters installed by
Start the project, enter the access address in the browser http://localhost:9080/baidu
, and find that the request is routed to the Baidu interface. The Zuul service is successfully built.
Zuul routing configuration
In the previous section, we used paths to match routing rules. The structure of path is as follows
# 其中customName 为用户自定义名称
zuul:
routes:
customName:
# 可使用的通配符有以下几种:
# ?:单个字符
# *:任意多个字符,不包含多级路径
# **:任意多个字符,包含多级路径
path: xxx
For url path matching, you can also use service name matching
zuul:
routes:
# users为用户自定义名称
users:
path: /users/**
# serviceId用于配置符合path的请求路径路由到的服务名称
serviceId: users-service
Service name matching is also available using simplified configuration
zuul:
routes:
service-provider:
path: /users/**
If only path is configured but not serviceld, customName is equivalent to the service name, that is, service-provider will be regarded as the service name. Use serviceId to register the zuul service to the registration center, such as Eureka, so as to pull the registered service list name to complete the call.
If you want to troubleshoot the configuration, you can use ignored-services
zuul:
ignoredServices: "*"
routes:
users:
path: /users/**
ignored-services allows you to configure a list of services that are not managed by Zuul. Multiple service names are separated by numbers. The configured services will not be proxied by Zuul. In the above example, all services except user services are ignored.
The routing prefix can be zuul.prefix
configured via , for example:
zuul:
prefix: /api
routes:
users:
path: /users/**
Configure the request path prefix. All requests based on this prefix are proxied by the Zuul gateway.
Zuul filter
Zuul defines filters to filter proxy requests and provide additional functional logic, such as permission verification, logging, etc. There is no direct communication between filters. In the request thread, status is shared through RequestContext, which is implemented internally using ThreadLocal.
Zuul filters are divided into pre-filtering, post-routing filtering, post-filtering and exception filtering:
- Pre-filtering: filtering logic that is executed immediately after the request enters Zuul
- Post-routing filtering: After the request enters Zuul, Zuul implements request routing and performs filtering logic before the remote service is called.
- Post-filtering: Execute filtering logic after the remote service call is completed
- Exception filtering: Execute filtering logic when an exception occurs in any filter or there is no result feedback from the remote service call (call timeout)
The ZuulFilter class and its parent class IZuulFilter provide a total of four abstract methods:
- filterType: Returns string data, representing the type of the current filter. Optional values are:
- pre: pre-filter, executed before the request is routed, usually used to handle identity authentication, logging, etc.
- route: called after the route is executed and before the service is called.
- error: Executed when an exception occurs in any filter or there is no feedback from the remote service call (timeout), usually used to handle
exceptions - post: is called after the route or error is executed. It is generally used to collect service information, collect statistics on service performance indicators, etc. It can also perform special processing on the response results.
- filterOrder: Returns int data, used to customize the execution order for multiple filters of the same filterType. The smaller the return value, the higher the priority of the execution order.
- shouldFilter: Returns boolean data, representing whether the current filter is effective
- run: specific filter execution logic
Specific examples are as follows:
@Component
public class tokenFilter extends ZuulFilter {
@Override
public String filterType() {
//定义过滤器的类型,pre 表示在请求被路由前执行
return "pre";
}
@Override
public int filterOrder() {
//返回int 数据,用于为同一种 filterType 的多个过滤器定制执行顺序
//返回值越小,执行顺序越优先
return 0;
}
@Override
public boolean shouldFilter() {
//判断过滤器是否生效,true 代表生效
return true;
}
@Override
public Object run() throws ZuulException {
//获取上下文
RequestContext currentContext = RequestContext.getCurrentContext();
//获取 request 对象
HttpServletRequest request = currentContext.getRequest();
//从请求头获取 token 的参数
String userToken = request.getParameter("token");
if (StringUtils.isEmpty(userToken)) {
//返回错误提示
//false:表示不会继续往下执行,不会调用服务接口,直接响应给客户
currentContext.setSendZuulResponse(false);
currentContext.setResponseBody("token is null");
currentContext.setResponseStatusCode(401);
return null;
}
//否则正常执行,调用服务接口...
return null;
}
}