Zuul作为微服务系统的网关组件,用于构建边界服务(Edge Service),致力于动态路由、过滤、监控、弹性伸缩和安全。其在微服务架构中有着重要的作用,主要体现在以下六个方面:
- Zull、Ribbon以及Eureka相结合可以实现智能路由和负载均衡的功能,Zull可以按照某种策略将请求分发到不同的实例上;
- 网关作为边界服务,将内部服务的API接口进行聚合并统一对外暴露接口。保护内部服务的API接口,防止内部服务被外界调用泄露敏感信息;
- 网关可以对用户的身份权限进行认证,防止非法请求API接口;
- 网关可以实现监控功能,实时日志输出,对请求进行记录;
- 网关可以用来实现流量监控,在高流量的情况下,对服务进行降级;
- API接口从内部服务分离出来,便于测试
springBoot使用的是2.0.2.RELEASE版本 springCloud使用的是Finchley.RELEASE版本。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<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>
配置文件
zuul:
routes:
# /myProduct/product/list -> /product/product/list
#aaaaa 表示这个名字可以随便写,下面是简洁的写法
aaaaa:
path: /myProduct/**
serviceId: product
#简洁写法
# product: /myProduct/**
启动类
@SpringBootApplication
@EnableZuulProxy
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
面向服务的路由
Spring Cloud Zuul 与 Spring Cloud Eureka 可以实现无缝对接实现面向服务的路由。我们让路由的path映射到具体的服务上,而具体的url交由Eureka的服务发现机制去自动维护。面向服务的路由默认实现了负载均衡。
商品服务原来的访问地址是:http://localhost:8080/product/list
使用zuul网关也可以实现路由功能:http://localhost:8002/product/product/list或者http://localhost:8002/myProduct/product/list
都可以进行服务的访问。
其中product或myProduct(自定义)为微服务的名称,可以任意定义。根据配置从注册中心拿到真实的路由地址。
/product/list 表示的是服务的真实的请求地址。
由于默认情况下所有Eureka上的服务都会被Zuul自动创建映射关系进行路由,这会使得一些我们不希望对外开放的服务也被外部访问到。这个时候我们可以配置zuul.ignored-services
参数来设置一个服务名匹配表达式进行判断,如果服务名匹配表达式,那么Zull将跳过这个服务,不为其创建路由规则。例如:zuul.ignored-services=*
表示对所有的服务不自动创建路由规则,这样我们就需要为每个服配置路由规则。
#排除某些路由
# ignored-patterns:
# - /**/product/listForOrder
Zuul的过滤器
Zull有请求过滤的功能,其过滤器可以在Http请求的发起和响应返回期间执行一系列的过滤器。Zuul包扩以下四种过滤器:
- PRE: 该类型的filters在Request routing到源web-service之前执行。可以进行一些权限认证,日志记录,或者额外给Request增加一些属性供后续的filter使用;
- ROUTING:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service;
- POST:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端;
- ERROR:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。
Zuul过滤器具有以下关键特性:
- Type(类型):Zuul过滤器的类型,这个类型决定过滤器在哪个阶段执行,例如:pre,post等阶段;
- Execution Order(执行顺序):规定了过滤器的执行顺序,Order的值越小,越先执行;
- Criteria(标准):Filters执行所需条件
- Action(行动):如果符合执行条件,则执行Action(具体逻辑代码)
Zuul请求的生命周期如图所示:
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
@Component
public class TokenFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//这里从url参数里获取, 也可以从header里获取
String token = request.getParameter("token");
if (StringUtils.isEmpty(token)) {
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
requestContext.setResponseBody("token is undefined...");
}
return null;
}
}